簡體   English   中英

MongoDB - 如果不存在則插入,否則跳過

[英]MongoDB- Insert if it doesn't exist, else skip

是否可以在有條件的情況下插入 Mongo;

//Pseudo code

Bulk Insert Item :

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

如果我進行單次插入,它可能會返回錯誤或在集合中插入,但是否可以批量插入?

根據您想如何處理事情,您在這里有兩個真正的選擇:

  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
})

正如已經說過的,“如果它不存在則插入”可以通過使用將upsert選項設置為 true 的update命令來實現。 以下是使用 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文檔中的更多信息。

使用setOnInsert

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

MongoDB 4.4 版

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM