- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
想象一下以下模型:
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);
});
})
}
这里我有些疑惑:
最佳答案
查看更新是否应用于类似 $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()
方法,将可靠地返回一个结果,告诉您是否实际修改了任何内容:
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
的东西。这实际上并没有改变值,因为提供的值等于文档中已经存在的值。
在仔细查看文档时,您可能会想到的另一种情况是实际检查“原始结果”并查看文档是否被修改。这个在规范中其实有一个指标。
问题是(以及需要对 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
}
因此,即使在努力从回调响应中获取“第三个”参数之后,我们仍然没有得到有关更新的正确信息。
因此,如果您想通过单个请求“可靠地”执行此操作( 而您不能通过多个请求可靠地执行此操作,因为文档可能会更改之间!) 那么你的两个选择是:
检查返回的文档以查看您要删除的数据是否仍然存在。
忘记返回文档并相信 .update()
总是告诉你“真相”;)
您使用其中的哪一个取决于应用程序的使用模式,但这是返回“可靠”结果的两种不同方式。
所以为了确定,这里有一个 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/
想象一下以下模型: var Office = { id: 1, name: "My Office", branches: [ { adddr
从名称 FindOneAndUpdate() 我明白这是一个原子操作。 如果我想找到 10 个项目(Limit(10))并全部更新它们怎么办? 例如,将状态字段设置为“进行中”? 使用 MongoDb
我正在尝试使用 mongo findAndUpdate 更新多个文档并不断收到语法错误: db.forecasts.findAndModify({ query: {forDate: ISODat
我正在尝试在更新之前对我的架构运行验证,这是它的代码。 架构 var workSchema = mongoose.Schema({ location: { type: String,
我正在使用 Update 和 FindAndModify,但现在我读到 Update 和 FindAndModify 是原子的(http://docs.mongodb.org/manual/tutor
我正在尝试创建一个由 Controller 和路由分隔的 nodejs API。我试图在多个集合中查找和更新,然后将它们放在多个 promise 中以返回单个响应,但我只得到一个 null 我在下面做
我想通过 Schema.findByIdAndUpdate(...) 将数组附加到 mongoose 中的现有数组。它应该看起来像这样: Schema.findByIdAndUpdate(id, {
我需要每分钟在 mongo 集合中插入 1000 个项目以防止重复。 使用findAndUpdate/Upsert,服务器性能会下降很多。 在不检查重复项的情况下保存项目,服务器不会变慢,但我需要一个
根据经验,findAndUpdate() 之后似乎不需要 flush(),我只是找不到在 Doctrine ODM/MongoDB 文档中的任何地方明确说明这一点(我也懒得去读太多的源代码)。 fin
我是一名优秀的程序员,十分优秀!