MongoDB-如果不存在则插入,否则跳过

时间:2015-09-07 02:40:33

标签: javascript node.js mongodb mongoose mongodb-query

是否可以在条件中插入Mongo;

//Pseudo code

Bulk Insert Item :

If Key exists
    Skip, don't throw error
If key does not exist
    Add item

如果我执行单个插入,可能会在集合中返回错误或插入,但是可以批量吗?

3 个答案:

答案 0 :(得分:22)

根据你想要处理的事情,你有两个真正的选择:

  1. 如果密钥数据存在,使用MongoDB的upsert功能实质上“查找”。如果没有,那么您只会将数据传递给$setOnInsert,而且不会触及任何其他内容。

  2. 批量使用“UnOrdered”操作。即使返回错误,整批更新仍将继续,但错误报告就是这样,并且任何非错误的内容都将被评估。

  3. 整个例子:

    var async = require('async'),
        mongoose = require('mongoose'),
        Schema = mongoose.Schema;
    
    var testSchema = new Schema({
      "_id": Number,
      "name": String
    },{ "_id": false });
    
    var Test = mongoose.model('Test',testSchema,'test');
    
    mongoose.connect('mongodb://localhost/test');
    
    var data = [
      { "_id": 1, "name": "One" },
      { "_id": 1, "name": "Another" },
      { "_id": 2, "name": "Two" }
    ];
    
    async.series(
      [
        // Start fresh
        function(callback) {
          Test.remove({},callback);
        },
    
        // Ordered will fail on error. Upserts never fail!
        function(callback) {
          var bulk = Test.collection.initializeOrderedBulkOp();
          data.forEach(function(item) {
            bulk.find({ "_id": item._id }).upsert().updateOne({
              "$setOnInsert": { "name": item.name }
            });
          });
          bulk.execute(callback);
        },
    
        // All as expected
        function(callback) {
          Test.find().exec(function(err,docs) {
            console.log(docs)
            callback(err);
          });
        },
    
    
        // Start again
        function(callback) {
          Test.remove({},callback);
        },
    
        // Unordered will just continue on error and record an error
        function(callback) {
          var bulk = Test.collection.initializeUnorderedBulkOp();
          data.forEach(function(item) {
            bulk.insert(item);
          });
          bulk.execute(function(err,result) {
            callback(); // so what! Could not care about errors
          });
        },
    
    
        // Still processed the whole batch
        function(callback) {
          Test.find().exec(function(err,docs) {
            console.log(docs)
            callback(err);
          });
        }
      ],
      function(err) {
        if (err) throw err;
        mongoose.disconnect();
      }
    );
    

    请注意,当前驱动程序中的“已更改操作”是.execute() 上的结果响应将返回要抛出的错误对象,而之前的版本没有使用“Un” - 订购“操作。

    这使得您的代码必须永远不依赖于单独返回的err,并且您应该将返回的result作为完整的错误分类。

    尽管如此,无序时,无论发生多少错误,批次都会一直持续到结束。那些不是错误的事情将照常进行。

    这真的归结为“序列重要”。如果是这样,那么您需要“有序”操作,并且您只能通过使用“upserts”来避免重复键。否则使用“无序”,但要注意错误返回以及它们实际意味着什么。

    此外,当使用.collection从基本驱动程序获取底层集合对象以启用“批量”操作时,请始终确保始终首先调用“某些”mongoose方法。

    如果没有这个,就没有保证使用本机驱动程序方法连接到数据库,因为它是为mongoose方法处理的,因此操作将因无连接而失败。

    首先“触发”mongoose方法的替代方法是将应用程序逻辑包装在事件监听器中以进行连接:

    mongoose.connection.on("open",function(err) {
        // app logic in here
    })
    

答案 1 :(得分:2)

如前所述,可以通过使用update命令并将upsert选项设置为true来实现“如果不存在则插入”。使用3.x node.js驱动程序的方法如下:

let ops = [];
ops.push({ updateOne: { filter: {key:"value1"}, update: {} }, { upsert:true } });
ops.push({ updateOne: { filter: {key:"value2"}, update: { $set:{/*...*/} } }, { upsert:true } });
ops.push({ updateOne: { filter: {key:"value3"}, update: { { $setOnInsert:{/*...*/} } } }, { upsert:true } });
// < add more ops here >
await db.collection("my-collection").bulkWrite(ops, {ordered:false});

如果filter返回零结果,则将使用过滤条件创建一个新文档,并且$set更新(如果有)。如果您使用$setOnInsert,则更新仅适用于新文档。

发布此示例,因为它对我的情况非常有用。文档中有db.collection.bulkWrite的更多信息。

答案 2 :(得分:1)

使用setOnInsert

db.collection('collection').updateOne(
     { _id: data._id },
    { $setOnInsert: { ...data } },
    { upsert: true },
  )