猫鼬会覆盖文档,而不是$ set字段 [英] Mongoose overwrite the document rather that `$set` fields

查看:83
本文介绍了猫鼬会覆盖文档,而不是$ set字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

说,我有一个文件:

{
  _id: 'some_mongodb_id',
  name: 'john doe',
  phone: '+12345678901',
}

我要更新此文档:

.findOneAndUpdate({_id: 'some_mongodb_id'}, {name: 'Dan smith'})

结果应该是这样:

{
  _id: 'some_mongodb_id',
  name: 'Dan smith',
}

应删除未指定的属性.

我该怎么做?

推荐答案

实际上,但由于猫鼬实际上是在秘密"进行幕后的更新,因此,这实际上是您提交给常规MongoDB的默认操作功能.

Actually, but for the fact that mongoose is actually "messing with" the update under the covers, this is actually the default action of your submission to a regular MongoDB function.

所以猫鼬认为这是明智"的一种便捷方法,可以假定"您打算发布 $set 此处的指令.由于您实际上不想在这种情况下执行此操作,因此您可以通过{ overwrite: true }在传递给任何.update()方法的选项中关闭该行为:

So mongoose deems it "wise" as a convenience method to "presume" you meant to issue a $set instruction here. Since you actually do not want to do that in this case, you turn off that behavior via { overwrite: true } in the options passed to any .update() method:

作为一个完整的例子:

const mongoose = require('mongoose'),
      Schema = mongoose.Schema;

mongoose.Promise = global.Promise;
mongoose.set('debug',true);

const uri = 'mongodb://localhost/test',
      options = { useMongoClient: true };

const testSchema = new Schema({
  name: String,
  phone: String
});

const Test = mongoose.model('Test', testSchema);

function log(data) {
  console.log(JSON.stringify(data,undefined,2))
}

(async function() {

  try {

    const conn = await mongoose.connect(uri,options);

    // Clean data
    await Promise.all(
      Object.keys(conn.models).map( m => conn.models[m].remove({}) )
    );

    // Create a document
    let test = await Test.create({
      name: 'john doe',
      phone: '+12345678901'
    });
    log(test);

    // This update will apply using $set for the name
    let notover = await Test.findOneAndUpdate(
      { _id: test._id },
      { name: 'Bill S. Preston' },
      { new: true }
    );
    log(notover);

    // This update will just use the supplied object, and overwrite
    let updated = await Test.findOneAndUpdate(
      { _id: test._id },
      { name: 'Dan Smith' },
      { new: true, overwrite: true }
    );
    log(updated);


  } catch (e) {
    console.error(e);
  } finally {
    mongoose.disconnect();
  }

})()

产生:

Mongoose: tests.remove({}, {})
Mongoose: tests.insert({ name: 'john doe', phone: '+12345678901', _id: ObjectId("596efb0ec941ff0ec319ac1e"), __v: 0 })
{
  "__v": 0,
  "name": "john doe",
  "phone": "+12345678901",
  "_id": "596efb0ec941ff0ec319ac1e"
}
Mongoose: tests.findAndModify({ _id: ObjectId("596efb0ec941ff0ec319ac1e") }, [], { '$set': { name: 'Bill S. Preston' } }, { new: true, upsert: false, remove: false, fields: {} })
{
  "_id": "596efb0ec941ff0ec319ac1e",
  "name": "Bill S. Preston",
  "phone": "+12345678901",
  "__v": 0
}
Mongoose: tests.findAndModify({ _id: ObjectId("596efb0ec941ff0ec319ac1e") }, [], { name: 'Dan Smith' }, { new: true, overwrite: true, upsert: false, remove: false, fields: {} })
{
  "_id": "596efb0ec941ff0ec319ac1e",
  "name": "Dan Smith"
}

显示文档被覆盖",因为我们取消了 $set 操作,否则将进行插值.这两个示例首先显示时没有overwrite选项,该选项应用了 修饰符,然后加上" overwrite选项,将尊重您为更新"传递的对象,并且没有这样的

Showing the document is "overwritten" because we suppressed the $set operation that otherwise would have been interpolated. The two samples show first without the overwrite option, which applies the $set modifier, and then "with" the overwrite option, where the object you passed in for the "update" is respected and no such $set modifier is applied.

注意,这是MongoDB节点驱动程序默认"执行此操作的方式.因此,添加隐式" $set 的行为是由猫鼬完成的,除非您不这样做.

Note, this is how the MongoDB Node driver does this "by default". So the behavior of adding in the "implicit" $set is being done by mongoose, unless you tell it not to.

注意真正的替换"方法实际上是使用replaceOne作为之王. 不允许 在语句中使用原子运算符(如$set),如果尝试使用,则会出错.

NOTE The true way to "replace" would actually be to use replaceOne, either as the API method of replaceOne() or through bulkWrite(). The overwrite is a legacy of how mongoose wants to apply $set as described and demonstrated above, however the MongoDB official API introduces replaceOne as a "special" king of update() operation which does not allow the usage of atomic operators like $set within the statement and will error if you try.

这在语义上更加清晰,因为 replace 非常清楚地了解了该方法的实际用途.在标准API中,对update()变体的调用当然仍然允许您省略原子运算符,并且无论如何都只会替换内容.但是应该发出警告.

This is much clearer semantically since replace reads very clearly as to what the method is actually used for. Within standard API calls to the update() variants of course still allow you to omit the atomic operators and will just replace content anyway. But warnings should be expected.

这篇关于猫鼬会覆盖文档,而不是$ set字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆