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

Bas*_*wer 17 javascript mongoose mongodb node.js mongodb-query

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

//Pseudo code

Bulk Insert Item :

If Key exists
    Skip, don't throw error
If key does not exist
    Add item
Run Code Online (Sandbox Code Playgroud)

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

Bla*_*ven 23

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

  1. 如果密钥数据存在,则使用MongoDB的upsert功能实质上"查找".如果没有,那么您只传入数据,$setOnInsert并且不会触及任何其他内容.

  2. 在Bulk中使用"UnOrdered"操作.即使返回错误,整批更新仍将继续,但错误报告就是这样,并且任何非错误的内容都将被调用.

整个例子:

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();
  }
);
Run Code Online (Sandbox Code Playgroud)

请注意,当前驱动程序中的"已更改操作"是结果响应.execute() 返回要抛出的错误对象,其中先前版本未执行"未订购"操作.

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

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

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

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

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

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

mongoose.connection.on("open",function(err) {
    // app logic in here
})
Run Code Online (Sandbox Code Playgroud)


Mba*_*nda 8

使用setOnInsert

db.collection('collection').updateOne(
     { _id: data._id },
    { $setOnInsert: { ...data } },
    { upsert: true },
  )
Run Code Online (Sandbox Code Playgroud)

MongoDB 版本 4.4

https://docs.mongodb.com/manual/reference/operator/update/setOnInsert/


小智 5

正如已经说过的,“可以通过插入设置为true 的update命令upsert来实现”。使用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});
Run Code Online (Sandbox Code Playgroud)

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

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