MongoDB:过滤_id == obj._id时,插入时不将obj._id设置为null

时间:2019-11-19 20:58:41

标签: mongodb

我想配置一个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

3 个答案:

答案 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:trueReference

,则概括地说,您不能使用_id插入新文档