gpt4 book ai didi

javascript - FindAndUpdate 如何检查文档是否真的更新了

转载 作者:可可西里 更新时间:2023-11-01 10:15:11 26 4
gpt4 key购买 nike

想象一下以下模型:

var Office = 
{
id: 1,
name: "My Office",
branches:
[
{
adddress: "Some street, that avenue",
isPrincipal: true,
},
{
adddress: "Another address",
isPrincipal: false,
},
]
}

我想删除一个分支,但我们不能让用户从办公室中删除主要分支。所以这是我的功能:

remove: function(body)
{
return new Promise(function(resolve, reject)
{
return Office.findByIdAndUpdate(1, { $pull: {'branches': {_id: body.branch.id}}}, { new: true })
.then(function(updatedOffice){
resolve(updatedOffice)
})
.catch(function(error){
reject(error);
});

})
}

这里我有些疑惑:

  1. 如您所见,我没有在 isPrincipal 属性中包含另一个 WHERE,这是因为我不知道如何确定 office 对象是否实际发生了更改。因为该对象将始终被检索但是...我怎么才能确定这一点?
  2. FindByIdAndUpdate 是最好的方法吗,因为我们不能让用户删除主要分支,如果他试图这样做,我们必须显示警告。

最佳答案

查看更新是否应用于类似 $pull 的唯一真正可靠的方法基本上是检查返回的文件,看看你想要的数据是$pull是否仍然存在。

这适用于任何 "findAndUpdate"各种行动,这是有正当理由的,而且普通的.update()也是如此。实际上会“可靠地”告诉您是否确实进行了修改。

浏览案例:

查看返回内容

这主要涉及查看返回文档中的数组,以查看我们要求删除的内容是否确实存在:

var pullId = "5961de06ea264532c684611a";

Office.findByIdAndUpdate(1,
{ "$pull": { "branches": { "_id": pullId } } },
{ "new": true }
).then(office => {
// Check if the supplied value is still in the array
console.log(
"Still there?: %s",
(office.branches.find( b => b._id.toHexString() === pullId))
? true : false
);
}).catch(err => console.error(err))

我们使用 .toHexString()为了比较 ObjectId 的实际值,因为 JavaScript 不会与“对象”“相等”。如果提供的内容已经“转换”为 ObjectId 值,您将同时检查“左”和“右”,但在这种情况下我们知道另一个输入是“字符串”。

就用.update(),“靠谱”

此处要考虑的另一种情况会质疑您是否“确实需要”返回的修改后的数据。因为.update()方法,将可靠地返回一个结果,告诉您是否实际修改了任何内容:

Office.update(
{ "_id": 1 },
{ "$pull": { "branches": { "_id": pullId } } },
).then(result => {
log(result);
}).catch(err => console.error(err))

这里的 result 看起来像:

{
"n": 1,
"nModified": 1, // <--- This always tells the truth, and cannot lie!
"opTime": {
"ts": "6440673063762657282",
"t": 4
},
"electionId": "7fffffff0000000000000004",
"ok": 1
}

并且其中 nModified 是一个“真实”的指标,表明某些内容是否“实际更新”。因此,如果它是 1,那么 $pull 实际上会产生影响,但是当 0 时,实际上并没有从数组中删除任何内容,也没有任何内容被修改。

这是因为该方法实际上使用了更新后的 API,它确实具有表明实际修改的可靠结果。这同样适用于类似 $set 的东西。这实际上并没有改变值,因为提供的值等于文档中已经存在的值。

findAndModify 谎言!

在仔细查看文档时,您可能会想到的另一种情况是实际检查“原始结果”并查看文档是否被修改。这个在规范中其实有一个指标。

问题是(以及需要对 Promises 做更多的工作)结果实际上并不真实:

var bogusId = "5961de06ea264532c684611a"; // We know this is not there!

Promise((resolve,reject) => {
Office.findByIdAndUpdate(1,
{ "$pull": { "branches": { "_id": bogusId } } },
{ "new": true, "passRawResult" },
(err,result,raw) => { // We cannot pass multiple results to a Promise
if (err) reject(err);
resolve({ result, raw }); // So we wrap it!
}
)
})
.then(response => log(response.raw))
.catch(err => console.error(err));

这里的问题是,即使我们“知道”这不应该修改,响应却另有说明:

{
"lastErrorObject": {
"updatedExisting": true,
"n": 1 // <--- LIES! IT'S ALL LIES!!!
},
"value": {
"_id": 1,
"name": "My Office",
"branches": [
{
"address": "Third address",
"isPrincipal": false,
"_id": "5961de06ea264532c6846118"
}
],
"__v": 0
},
"ok": 1,
"_kareemIgnore": true
}

因此,即使在努力从回调响应中获取“第三个”参数之后,我们仍然没有得到有关更新的正确信息。


总结

因此,如果您想通过单个请求“可靠地”执行此操作( 而您不能通过多个请求可靠地执行此操作,因为文档可能会更改之间!) 那么你的两个选择是:

  1. 检查返回的文档以查看您要删除的数据是否仍然存在。

  2. 忘记返回文档并相信 .update()总是告诉你“真相”;)

您使用其中的哪一个取决于应用程序的使用模式,但这是返回“可靠”结果的两种不同方式。


一点 list

所以为了确定,这里有一个 list ,它遍历了所有示例并演示了它们实际返回的内容:

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

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

mongoose.connect('mongodb://localhost/test');

const branchesSchema = new Schema({
address: String,
isPrincipal: Boolean
});

const officeSchema = new Schema({
_id: Number,
name: String,
branches: [branchesSchema]
},{ _id: false });

const Office = mongoose.model('Office', officeSchema);

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

const testId = "5961a56d3ffd3d5e19c61610";

async.series(
[
// Clean data
(callback) =>
async.each(mongoose.models,(model,callback) =>
model.remove({},callback),callback),

// Insert some data and pull
(callback) =>
async.waterfall(
[
// Create and demonstrate
(callback) =>
Office.create({
_id: 1,
name: "My Office",
branches: [
{
address: "Some street, that avenue",
isPrincipal: true
},
{
address: "Another address",
isPrincipal: false
},
{
address: "Third address",
isPrincipal: false
}
]
},callback),

// Demo Alternates
(office,callback) =>
async.mapSeries(
[true,false].map((t,i) => ({ t, branch: office.branches[i] })),
(test,callback) =>
(test.t)
? Office.findByIdAndUpdate(office._id,
{ "$pull": { "branches": { "_id": test.branch._id } } },
{ "new": true , "passRawResult": true },
(err,result,raw) => {
if (err) callback(err);
log(result);
log(raw);
callback();
})
: Office.findByIdAndUpdate(office._id,
{ "$pull": { "branches": { "_id": test.branch._id } } },
{ "new": true } // false here
).then(result => {
log(result);
console.log(
"Present %s",
(result.branches.find( b =>
b._id.toHexString() === test.branch._id.toHexString() ))
? true : false
);
callback();
}).catch(err => callback(err)),
callback
)
],
callback
),

// Find and demonstate fails
(callback) =>
async.waterfall(
[
(callback) => Office.findOne({},callback),

(office,callback) =>
async.eachSeries([true,false],(item,callback) =>
(item)
? Office.findByIdAndUpdate(office._id,
{ "$pull": { "branches": { "_id": testId } } },
{ "new": true, "passRawResult": true },
(err,result,raw) => {
if (err) callback(err);
log(result);
log(raw);
callback();
}
)
: Office.findByIdAndUpdate(office._id,
{ "$pull": { "branches": { "_id": testId } } },
{ "new": true }
).then(result => {
console.log(result);
console.log(
"Present %s",
(result.branches.find( b =>
b._id.toHexString() === office.branches[0]._id.toHexString()))
? true : false
);
callback();
})
.catch(err => callback(err)),
callback)

],
callback
),

// Demonstrate update() modified shows 0
(callback) =>
Office.update(
{},
{ "$pull": { "branches": { "_id": testId } } }
).then(result => {
log(result);
callback();
})
.catch(err => callback(err)),

// Demonstrate wrapped promise
(callback) =>
Office.findOne()
.then(office => {
return new Promise((resolve,reject) => {
Office.findByIdAndUpdate(office._id,
{ "$pull": { "branches": { "_id": testId } } },
{ "new": true, "passRawResult": true },
(err,result,raw) => {
if (err) reject(err);
resolve(raw)
}
);
})
})
.then(office => {
log(office);
callback();
})
.catch(err => callback(err))

],
(err) => {
if (err) throw err;
mongoose.disconnect();
}
);

它产生的输出:

Mongoose: offices.remove({}, {})
Mongoose: offices.insert({ _id: 1, name: 'My Office', branches: [ { address: 'Some street, that avenue', isPrincipal: true, _id: ObjectId("5961e5211a73e8331b44d74b") }, { address: 'Another address', isPrincipal: false, _id: ObjectId("5961e5211a73e8331b44d74a") }, { address: 'Third address', isPrincipal: false, _id: ObjectId("5961e5211a73e8331b44d749") } ], __v: 0 })
Mongoose: offices.findAndModify({ _id: 1 }, [], { '$pull': { branches: { _id: ObjectId("5961e5211a73e8331b44d74b") } } }, { new: true, passRawResult: true, upsert: false, remove: false, fields: {} })
{
"_id": 1,
"name": "My Office",
"__v": 0,
"branches": [
{
"address": "Another address",
"isPrincipal": false,
"_id": "5961e5211a73e8331b44d74a"
},
{
"address": "Third address",
"isPrincipal": false,
"_id": "5961e5211a73e8331b44d749"
}
]
}
{
"lastErrorObject": {
"updatedExisting": true,
"n": 1
},
"value": {
"_id": 1,
"name": "My Office",
"branches": [
{
"address": "Another address",
"isPrincipal": false,
"_id": "5961e5211a73e8331b44d74a"
},
{
"address": "Third address",
"isPrincipal": false,
"_id": "5961e5211a73e8331b44d749"
}
],
"__v": 0
},
"ok": 1,
"_kareemIgnore": true
}
Mongoose: offices.findAndModify({ _id: 1 }, [], { '$pull': { branches: { _id: ObjectId("5961e5211a73e8331b44d74a") } } }, { new: true, upsert: false, remove: false, fields: {} })
{
"_id": 1,
"name": "My Office",
"__v": 0,
"branches": [
{
"address": "Third address",
"isPrincipal": false,
"_id": "5961e5211a73e8331b44d749"
}
]
}
Present false
Mongoose: offices.findOne({}, { fields: {} })
Mongoose: offices.findAndModify({ _id: 1 }, [], { '$pull': { branches: { _id: ObjectId("5961a56d3ffd3d5e19c61610") } } }, { new: true, passRawResult: true, upsert: false, remove: false, fields: {} })
{
"_id": 1,
"name": "My Office",
"__v": 0,
"branches": [
{
"address": "Third address",
"isPrincipal": false,
"_id": "5961e5211a73e8331b44d749"
}
]
}
{
"lastErrorObject": {
"updatedExisting": true,
"n": 1
},
"value": {
"_id": 1,
"name": "My Office",
"branches": [
{
"address": "Third address",
"isPrincipal": false,
"_id": "5961e5211a73e8331b44d749"
}
],
"__v": 0
},
"ok": 1,
"_kareemIgnore": true
}
Mongoose: offices.findAndModify({ _id: 1 }, [], { '$pull': { branches: { _id: ObjectId("5961a56d3ffd3d5e19c61610") } } }, { new: true, upsert: false, remove: false, fields: {} })
{ _id: 1,
name: 'My Office',
__v: 0,
branches:
[ { address: 'Third address',
isPrincipal: false,
_id: 5961e5211a73e8331b44d749 } ] }
Present true
Mongoose: offices.update({}, { '$pull': { branches: { _id: ObjectId("5961a56d3ffd3d5e19c61610") } } }, {})
{
"n": 1,
"nModified": 0,
"opTime": {
"ts": "6440680872013201413",
"t": 4
},
"electionId": "7fffffff0000000000000004",
"ok": 1
}
Mongoose: offices.findOne({}, { fields: {} })
Mongoose: offices.findAndModify({ _id: 1 }, [], { '$pull': { branches: { _id: ObjectId("5961a56d3ffd3d5e19c61610") } } }, { new: true, passRawResult: true, upsert: false, remove: false, fields: {} })
{
"lastErrorObject": {
"updatedExisting": true,
"n": 1
},
"value": {
"_id": 1,
"name": "My Office",
"branches": [
{
"address": "Third address",
"isPrincipal": false,
"_id": "5961e5211a73e8331b44d749"
}
],
"__v": 0
},
"ok": 1,
"_kareemIgnore": true
}

关于javascript - FindAndUpdate 如何检查文档是否真的更新了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44991907/

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