28

我希望有一个方法可以创建或更新策略文档。搜索并尝试像这样的不同技术,我为我的文档想出了一个空 _id。使用 findByIdAndUpdate 也有类似的效果。

我看到集合中插入了一个文档,但 _id 字段为空:

exports.savePolicy = function (plcy, callback) {
    console.log('priority is : ' + plcy.priority)
    try {
        var policy = new Policy(plcy);
        var query = {_id: plcy._id};  //this may be null
        var update = {
            name: plcy.name || defaults.policyDefaults.name,
            longDescription: plcy.longDescription || defaults.policyDefaults.longDescription,
            shortDescription: plcy.shortDescription || defaults.policyDefaults.shortDescription,
            priority: plcy.priority, colorHex: plcy.colorHex || defaults.policyDefaults.colorHex,
            settings: plcy.settings || [],
            parentPolicyId: plcy.parentPolicyId || null
        }

        Policy.findOneAndUpdate(query, update, {upsert: true}, function (err, data) {
            callback(err, data);
        });

    } catch (e) {
        log.error('Exception while trying to save policy: ' + e.message);
        callback(e, null);
    }

当 _id 不是更新时,有什么办法可以让 _id 不为空?

4

9 回答 9

21

null是 MongoDB 中的有效值_id,因此如果您不希望在新文档中使用它,则必须确保将null值替换为新ObjectID的 in query

var query = {_id: plcy._id};
if (!query._id) {
    query._id = new mongoose.mongo.ObjectID();
}

// the rest stays the same...
于 2014-12-21T15:09:08.130 回答
5

我遇到了同样的问题,无法找到让它工作的方法。我最终像这样编写了自己的 upsert 方法....

var upsert = function(model, data, f){
  if (!data._id) {
    model.create(data, f);
  } else {
    var id = data._id;
    delete data._id;
    model.findOneAndUpdate({_id: id}, data, f);
  }
}

这让我可以用一行代码为我的任何模型调用它......

upsert(Team, team, f);

可能有更好的方法来做到这一点,但这对我有用。我可以进行更新和插入,并且在插入时我没有得到空 _id。

于 2014-12-21T14:56:15.577 回答
3

感谢 JohnnyHK 在上面提供了有用的答案。我想出了一个单线,因为它被频繁使用:

query = args._id ? { _id: args._id } : { _id: new ObjectId() };

它依赖于以下要求:

const ObjectId = require('mongodb').ObjectID;
于 2017-12-27T16:14:58.043 回答
1

如果有 ID,则更新文档或如果没有 ID,则创建新文档的最简单方法是:

Model.findOneAndUpdate({ _id: id ?? new mongoose.Types.ObjectId() }, updates, { upsert: true });

请注意使用空值合并运算符 (??),它允许 0 作为有效 id。该updates对象不需要包含id属性,因为 mongoose 会自动添加它

如果没有文档匹配过滤器,MongoDB 将通过组合过滤器和更新插入一个,如下所示。

于 2021-09-07T10:04:14.353 回答
1

这可能很有用(来自文档):

如果您在查询参数或替换文档中指定 _id 字段,MongoDB 会在插入的文档中使用该 _id 字段。

所以当你写:

model.findOneAndUpdate({_id: id}, data, f);

而且,idnull会插入一个带有nullid 的文档。

于 2020-06-11T14:55:24.190 回答
1

我没有使用 Mongoose,但我遇到了与 MongoDB 类似的问题。对于插入新对象时的 Upsert 操作,MongoDB 设置null_id.

我在打电话:

findOneAndUpdate({my_id:'my_unique_id'}, obj, {upsert: true})

obj._id在哪里undefined

问题是_id存在于键列表中Object.keys(obj)。我发现我正在分配obj._id = some_variable, where some_variableis undefined,这导致_id出现在键列表中。

我通过在 upsert 之前调用来应用解决方法:

if (_.isUndefined(obj._id)) {
  delete obj._id;
}
于 2017-02-11T23:04:54.823 回答
0

由于我们现在可以在 JavaScript 中解构对象时添加默认属性,因此在检查文档是否存在的情况下,我发现这是通过现有 _id 查询或在同一操作中创建新的最简单的方法,避免空 id 问题:

// someController.js 使用 POST 路由

async function someController(req, res) {
  try {
  const {
    // the default property will only be used if the _id doesn't exist
    _id: new mongoose.Types.ObjectId(),
    otherProp,
    anotherProp
  } = req.body;
  const createdOrUpdatedDoc = await SomeModel.findOneAndUpdate(
    {
      _id
    },
    {
      otherProp,
      anotherProp
    },
    {
      new: true,
      upsert: true
    }
  ).exec();
  return res.json(201).json(createdOrUpdatedDoc);
  } catch (error) {
    return res.json(400).send({
      error,
      message: "Could not do this"
    })
  }
}
于 2020-01-23T08:01:17.837 回答
-2

尝试将“新”参数设置为 true:

{ upsert: true, new: true }

更多信息:https ://github.com/Automattic/mongoose/issues/2939

于 2019-04-30T08:48:18.747 回答
-3

尝试在更新调用中将 upsert 参数设置为 true。从 mongoid 文档:http ://docs.mongodb.org/manual/reference/method/db.collection.update/#update-parameter

可选的。如果设置为 true,则在没有文档与查询条件匹配时创建一个新文档。默认值为 false,即在未找到匹配项时不插入新文档。

于 2014-05-29T18:58:22.707 回答