自动计算 mongodb 中的字段
Auto calculating fields in mongodb
假设 MongoDB 中有文档,看起来像这样:
{
"lastDate" : ISODate("2013-14-01T16:38:16.163Z"),
"items":[
{"date":ISODate("2013-10-01T16:38:16.163Z")},
{"date":ISODate("2013-11-01T16:38:16.163Z")},
{"date":ISODate("2013-12-01T16:38:16.163Z")},
{"date":ISODate("2013-13-01T16:38:16.163Z")},
{"date":ISODate("2013-14-01T16:38:16.163Z")}
]
}
甚至像这样:
{
"allAre" : false,
"items":[
{"is":true},
{"is":true},
{"is":true},
{"is":false},
{"is":true}
]
}
顶级字段 "lastDate"
和 "allAre"
每次数组中的数据更改时都应重新计算。 "lastDate"
应该是最大的 "date"
。仅当所有项目都将 "is"
设为真时,"allAre"
才应等于真。
我应该如何构建我的查询以通过 MongoDB 实现这种行为?
在插入时预先计算一些值而不是在获取请求期间计算它们是否被认为是一种好的做法?
MongoDB 不能通过 1 个查询来满足您的要求。
但是可以分两步查询。
首先,将新值压入数组:
db.Test3.findOneAndUpdate(
{_id: ObjectId("58047d0cd63cf401292fe0ad")},
{$push: {"items": {"date": ISODate("2013-01-27T16:38:16.163+0000")}}},
{returnNewDocument: true},
function (err, result) {
}
);
然后更新 "lastDate" 仅当小于上次推送时。
db.Test3.findOneAndUpdate (
{_id: ObjectId("58047d0cd63cf401292fe0ad"), "lastDate":{$lt: ISODate("2013-01-25T16:38:16.163+0000")}},
{$set: {"lastDate": ISODate("2013-01-25T16:38:16.163+0000")}},
{returnNewDocument: true},
function (err, result) {
}
);
需要第二个参数 "lastDate" 以避免竞争条件。这样你就可以确定 "lastDate" 里面肯定有 "highest date pushed".
关于您要求的第二个问题,您可以遵循类似的策略。仅在 {"_id":yourID, "items.is":false)}
时更新 {"allAre": false}
。基本上仅当某些子项具有值 'false' 时才设置 "false"。如果您没有找到包含此 属性 的文档,则不要更新任何内容。
// add a new Child to false
db.Test4.findOneAndUpdate(
{_id: ObjectId("5804813ed63cf401292fe0b0")},
{$push: {"items": {"is": false}}},
{returnNewDocument: true},
function (err, result) {
}
);
// update allAre to false if some child is false
db.Test4.findOneAndUpdate (
{_id: ObjectId("5804813ed63cf401292fe0b0"), "items.is": false},
{$set: {"allAre": false}},
{returnNewDocument: true},
function (err, result) {
}
);
假设 MongoDB 中有文档,看起来像这样:
{
"lastDate" : ISODate("2013-14-01T16:38:16.163Z"),
"items":[
{"date":ISODate("2013-10-01T16:38:16.163Z")},
{"date":ISODate("2013-11-01T16:38:16.163Z")},
{"date":ISODate("2013-12-01T16:38:16.163Z")},
{"date":ISODate("2013-13-01T16:38:16.163Z")},
{"date":ISODate("2013-14-01T16:38:16.163Z")}
]
}
甚至像这样:
{
"allAre" : false,
"items":[
{"is":true},
{"is":true},
{"is":true},
{"is":false},
{"is":true}
]
}
顶级字段 "lastDate"
和 "allAre"
每次数组中的数据更改时都应重新计算。 "lastDate"
应该是最大的 "date"
。仅当所有项目都将 "is"
设为真时,"allAre"
才应等于真。
我应该如何构建我的查询以通过 MongoDB 实现这种行为?
在插入时预先计算一些值而不是在获取请求期间计算它们是否被认为是一种好的做法?
MongoDB 不能通过 1 个查询来满足您的要求。 但是可以分两步查询。
首先,将新值压入数组:
db.Test3.findOneAndUpdate(
{_id: ObjectId("58047d0cd63cf401292fe0ad")},
{$push: {"items": {"date": ISODate("2013-01-27T16:38:16.163+0000")}}},
{returnNewDocument: true},
function (err, result) {
}
);
然后更新 "lastDate" 仅当小于上次推送时。
db.Test3.findOneAndUpdate (
{_id: ObjectId("58047d0cd63cf401292fe0ad"), "lastDate":{$lt: ISODate("2013-01-25T16:38:16.163+0000")}},
{$set: {"lastDate": ISODate("2013-01-25T16:38:16.163+0000")}},
{returnNewDocument: true},
function (err, result) {
}
);
需要第二个参数 "lastDate" 以避免竞争条件。这样你就可以确定 "lastDate" 里面肯定有 "highest date pushed".
关于您要求的第二个问题,您可以遵循类似的策略。仅在 {"_id":yourID, "items.is":false)}
时更新 {"allAre": false}
。基本上仅当某些子项具有值 'false' 时才设置 "false"。如果您没有找到包含此 属性 的文档,则不要更新任何内容。
// add a new Child to false
db.Test4.findOneAndUpdate(
{_id: ObjectId("5804813ed63cf401292fe0b0")},
{$push: {"items": {"is": false}}},
{returnNewDocument: true},
function (err, result) {
}
);
// update allAre to false if some child is false
db.Test4.findOneAndUpdate (
{_id: ObjectId("5804813ed63cf401292fe0b0"), "items.is": false},
{$set: {"allAre": false}},
{returnNewDocument: true},
function (err, result) {
}
);