gpt4 book ai didi

node.js - Mongoose 覆盖文档而不是 `$set` 字段

转载 作者:IT老高 更新时间:2023-10-28 13:33:02 25 4
gpt4 key购买 nike

说,我有一个文件:

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

我想更新这个文档:

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

结果应该是这样的:

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

应删除未指定的属性。

我该怎么做?

最佳答案

实际上,但事实上 mongoose 实际上是在“搞乱”更新,这实际上是您提交给常规 MongoDB 函数的默认操作。

所以 mongoose 认为它是“明智的”作为“假定”您打算在此处发出 $set 指令的便捷方法。由于您实际上不想在这种情况下这样做,您可以通过传递给任何 .update() 方法的选项中的 { overwrite: true } 关闭该行为:

作为一个完整的例子:

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 选项,该选项应用 $set 修饰符,然后显示“with” overwrite 选项,其中您为“更新”传递的对象受到尊重,并且没有应用这样的 $set 修饰符。

注意,这是 MongoDB Node 驱动程序“默认”执行此操作的方式。所以添加“隐式”$set 的行为是由 mongoose 完成的,除非你告诉它不要这样做。


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.

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.

关于node.js - Mongoose 覆盖文档而不是 `$set` 字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45182011/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com