是否可以在条件中插入Mongo;
//Pseudo code
Bulk Insert Item :
If Key exists
Skip, don't throw error
If key does not exist
Add item
如果我执行单个插入,可能会在集合中返回错误或插入,但是可以批量吗?
答案 0 :(得分:22)
根据你想要处理的事情,你有两个真正的选择:
如果密钥数据存在,使用MongoDB的upsert功能实质上“查找”。如果没有,那么您只会将数据传递给$setOnInsert
,而且不会触及任何其他内容。
批量使用“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()
上的结果响应将返回要抛出的错误对象,而之前的版本没有使用“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 },
)