【问题标题】:MongoDB- Insert if it doesn't exist, else skipMongoDB-如果不存在则插入,否则跳过
【发布时间】:2015-12-02 12:29:26
【问题描述】:

是否可以在有条件的情况下插入Mongo;

//Pseudo code

Bulk Insert Item :

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

如果我做单次插入,它可能会返回错误或在集合中插入,但是 bulk 是否有可能?

【问题讨论】:

  • 阅读"upsert"。因为这就是 MongoDB 的方式。有 .upsert() 作为批量操作所需的修饰符。此外,$setOnInsert 只会在“插入”新文档时应用更改,如果唯一的操作在该块内,则不会应用更改。

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


【解决方案1】:

使用setOnInsert

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

Mongodb 4.4 版

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

【讨论】:

    【解决方案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 的文档中的更多信息。

    【讨论】:

      【解决方案3】:

      你有两个真正的选择,这取决于你想如何处理事情:

      1. 使用 MongoDB 的upsert 功能基本上“查找”关键数据是否存在。如果没有,那么您只需将数据传递给$setOnInsert,这不会涉及任何其他内容。

      2. 批量使用“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();
        }
      );
      

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

      这使得您的代码绝对不能单独依赖返回的err,并且您应该输入返回的result,而不是对错误进行完整分类。

      尽管如此,当无序时,无论发生多少错误,批处理都会持续到最后。不是错误的事情将照常提交。

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

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

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

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

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

      【讨论】:

        猜你喜欢
        • 2018-10-12
        • 2021-06-03
        • 2011-02-17
        • 2012-03-28
        • 2018-09-17
        • 1970-01-01
        • 2016-02-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多