我想配置一个upsert。如果我的对象上已经存在_id
,它会识别出该对象并更新匹配项。如果_id
不存在,则应插入新文档并生成_id。我希望{ _id: obj._id }
可以正常工作,但这会覆盖_id
的自动生成。该文档显示为_id: null
。是否有适用于此的过滤器?我需要路由以插入/更新代码内吗?
编辑:添加查询。
collection.updateOne(
{ _id: entity._id },
{ $set: entity },
{ upsert: true }
)
编辑:尝试删除。 即使删除属性,也没有运气。
const upsertTest = (collection) => {
const entity = { date: new Date() };
console.log(entity);
// { date: 2019-11-19T22:16:00.914Z }
const _id = entity._id;
delete entity._id;
console.log(entity);
// { date: 2019-11-19T22:16:00.914Z }
collection.updateOne(
{ _id: _id },
{ $set: entity },
{ upsert: true }
);
console.log(entity);
// { date: 2019-11-19T22:16:00.914Z }
}
但是新文档是这样的: screenshot of new document
答案 0 :(得分:0)
首先,_id
属性将始终存在,无论您是自行设置还是自动生成。因此,无需检查它是否存在。
upsert的语法如下:
db.collection.update({
_id: 'the id you want to check for' // can put any valid 'find' query here
}, {
$set: {
foo: 'bar',
biz: 'baz'
}
}, {
upsert: true
});
如果存在具有给定_id
的文档,则将使用$set
对象进行更新。如果不存在,将使用$set
对象的属性创建一个新对象。如果未在_id
对象中指定$set
,则将自动生成一个新的_id
值,或者将继续使用现有的_id
值。
此处的关键是使用$set
,而不是将对象放在那里。使用set将合并并替换属性。如果没有$set
,它将替换整个文档,并删除所有未设置的属性。
编辑:现在看到您进行的实际查询,建议您在设置实体之前从实体中删除_id
属性。这样可以确保它不被处理。
const _id = entity._id;
delete entity._id;
// now do your query using the new `_id` value for the ID.
答案 1 :(得分:0)
您在我们的评论中提到您正在使用local
数据库。 local
数据库允许_id
为空。使用任何其他数据库都可以解决您的问题。
答案 2 :(得分:0)
您必须使用$setOnInsert插入_id
let ObjectID = require('mongodb').ObjectID;
collection.updateOne(
{ _id: entity._id },
{ $set: entity,$setOnInsert:{_id:new ObjectID()}},
{ upsert: true }
)
顾名思义,它将在_id
上设置insert
如果您使用的是mongodb
,那么new ObjectID()
应该可以使用
如果它是mongoose
,则可以使用mongoose.Types.ObjectId()
生成新的ObjectID
好了,我找到了你的问题
版本3.0中的更改:当使用upsert:true执行update()且查询不匹配现有文档时,如果查询在_id字段上指定了条件,则MongoDB将拒绝插入新文档。
因此,如果您的查询使用的是upsert:true
,Reference
_id
插入新文档