MongoDB节点本机驱动程序创建重复文档

时间:2014-01-26 19:08:04

标签: node.js mongodb node-mongodb-native

使用mongodb-native-driver保存文档更新时,我收到了重复的文档。我第一次调用save()正确创建了文档,并添加了一个带有ObjectID值的_id。第二次调用使用原始ObjectID的文本_id创建一个新文档。例如,我最终得到:

> db.people.find()
{ "firstname" : "Fred", "lastname" : "Flintstone", "_id" : ObjectId("52e55737ae49620000fd894e") }
{ "firstname" : "Fred", "lastname" : "Flintstone with a change", "_id" : "52e55737ae49620000fd894e" }

我的第一次电话正确创建了Fred Flinstone。第二次调用将“带有更改”添加到姓氏,创建了第二个文档。

我正在使用MongoDB 2.4.8和mongo-native-driver 1.3.23。

这是我的NodeJS / Express端点:

app.post("/contacts", function (req, res) {
  console.log("POST /contacts, req.body: " + JSON.stringify(req.body));

  db.collection("people").save(req.body, function (err, inserted) {
    if (err) {
      throw err;
    } else {
      console.dir("Successfully inserted/updated: " + JSON.stringify(inserted));
      res.send(inserted);
    }
  });
});

以下是运行时日志消息:

POST /contacts, req.body: {"firstname":"Fred","lastname":"Flintstone"}
'Successfully inserted/updated: {"firstname":"Fred","lastname":"Flintstone","_id":"52e55737ae49620000fd894e"}'
POST /contacts, req.body: {"firstname":"Fred","lastname":"Flintstone with a change","_id":"52e55737ae49620000fd894e"}
'Successfully inserted/updated: 1'

为什么我的第二次更新现有记录?驱动程序是否未将_id值转换为ObjectID?

2 个答案:

答案 0 :(得分:3)

第二次发布的内容包含一个名为“_id”的字段,它是一个字符串。这就是问题所在。

查看文档,save method所做的是“简单的完整文档替换功能”。我不经常使用这个功能退出,所以这就是我猜的。该函数使用_id字段查找文档,然后将完整文档替换为您提供的文档。但是,您提供的是字符串_id。显然它不等于ObjectId。我认为你应该在传递给函数之前将它包装到ObjectId。

此外,根据文档不建议使用save方法。您应该使用update(可能带有upsert选项)而不是

答案 1 :(得分:1)

我不知道为什么会创建第二个文档,但为什么不使用更新功能(可能使用 upsert 运算符)?

更新操作的示例:

var query = { '_id': '52e55737ae49620000fd894e' };

db.collection('people').findOne(query, function (err, doc) {
    if (err) throw err;

    if (!doc) {
        return db.close();
    }

    doc['lastname'] = 'Flintstone with a change';

    db.collection('people').update(query, doc, function (err, updated) {
        if (err) throw err;

        console.dir('Successfully updated ' + updated + ' document!');

        return db.close();
    });
});

现在使用upsert运算符:

var query = { '_id': '52e55737ae49620000fd894e' };
var operator = { '$set': { 'lastname': 'Flintstone with a change' } };
var options = { 'upsert': true };

db.collection('people').update(query, operator, options, function (err, upserted) {
    if (err) throw err;

    console.dir('Successfully upserted ' + upserted + ' document!');

    return db.close();
});

不同之处在于upsert运算符将更新文档(如果存在),否则将创建一个新文档。使用upsert运算符时,应记住此操作可能未指定。这意味着如果您的查询中没有足够的信息来标识单个文档,则会插入一个新文档。