Javascript MongoDB - 如果不存在则插入,否则跳过
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32430384/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
MongoDB- Insert if it doesn't exist, else skip
提问by Basit Anwer
Is it possible to insert in Mongo with condition;
是否可以在有条件的情况下插入 Mongo;
//Pseudo code
Bulk Insert Item :
If Key exists
Skip, don't throw error
If key does not exist
Add item
If i do single inserts, it might return an error or insert in the collection, but is it possible in bulk?
如果我进行单次插入,它可能会返回错误或在集合中插入,但是否可以批量插入?
回答by Blakes Seven
You have two real choices here depending on how you want to handle things:
根据您想如何处理事情,您在这里有两个真正的选择:
Use upsertfunctionality of MongoDB to essentially "lookup" if the key data exists. If not then you only pass in data to
$setOnInsert
and that will not touch anything else.Use "UnOrdered" operations in Bulk. The whole batch of updates will continue even if an error is returned, but the error report(s) are just that, and anything that is not an error will be comitted.
如果关键数据存在,则使用MongoDB 的upsert功能从本质上“查找”。如果没有,那么您只将数据传递给
$setOnInsert
并且不会触及任何其他内容。批量使用“UnOrdered”操作。即使返回错误,整批更新也会继续,但错误报告仅此而已,任何不是错误的都将被提交。
Whole example:
整个例子:
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();
}
);
Note that the "changed action" in current drivers is that the result response on .execute()
willreturn an error object to be thrown, where previous releases did not do so with "Un-ordered" operations.
请注意,当前驱动程序中的“更改操作”是结果响应.execute()
将返回一个要抛出的错误对象,而以前的版本在“无序”操作中没有这样做。
This makes it imperative that your code never relies on the err
returned alone, and you should be inpspeting the returned result
instead for the full classification of errors.
这使得您的代码永远不能err
单独依赖于返回值,并且您应该检查返回值result
以进行完整的错误分类。
Nonetheless, when unordered then the batch continues until the end, no matter how many errors occur. Things that are not an error will be committed as normal.
尽管如此,当无序时,无论发生多少错误,批处理都会继续直到结束。不是错误的事情将照常提交。
This really comes down to "is sequence important". If so, then you need "Ordered" operations and you can only avoid duplicate keys by using "upserts". Otherwise use "unordered", but be aware of the error returns and what they actually mean.
这真的归结为“序列是否重要”。如果是这样,那么您需要“有序”操作,并且只能通过使用“upserts”来避免重复键。否则使用“无序”,但要注意错误返回及其实际含义。
Also, when using .collection
to get the underlying collection object from the base driver to enable "Bulk" operations, then always be sure that either "some" mongoose method has always been called first.
此外,当使用.collection
从基本驱动程序获取底层集合对象以启用“批量”操作时,请始终确保始终首先调用“某些”猫鼬方法。
Without that, there is no guaranteed connection to the database with the native driver methods as it is handled for the mongoose methods, so the operation will fail due to no connection.
没有它,就无法保证使用本机驱动程序方法连接到数据库,因为它是为 mongoose 方法处理的,因此操作将由于没有连接而失败。
The alternate to "firing" a mongoose method first, is to wrap your app logic in an event listener for the connection:
首先“触发”mongoose 方法的替代方法是将您的应用程序逻辑包装在连接的事件侦听器中:
mongoose.connection.on("open",function(err) {
// app logic in here
})
回答by Basit Anwer
As has already been said, "insert if it doesn't already exist" can be achieved by using the update
command with the upsert
option set to true. Here's how to do that with the 3.x node.js driver:
正如已经说过的,“如果它不存在则插入”可以通过使用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});
If the filter
returns zero results, a new document will be created using the filter conditions and the $set
updates (if any). If you use $setOnInsert
, then the updates are only applied to new docs.
如果filter
返回零结果,将使用过滤条件和$set
更新(如果有)创建一个新文档。如果您使用$setOnInsert
,则更新仅适用于新文档。
Posting this example because it would have been handy for my situation. More info in the docs for db.collection.bulkWrite.
发布此示例是因为它对我的情况很方便。db.collection.bulkWrite文档中的更多信息。
回答by Mbanda
Use setOnInsert
用 setOnInsert
db.collection('collection').updateOne(
{ _id: data._id },
{ $setOnInsert: { ...data } },
{ upsert: true },
)