自动计算mongodb中的字段

时间:2016-10-11 16:22:49

标签: mongodb calculated-field embedded-documents nosql

让我们说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"。仅当所有项目都"allAre"为真时,"is"才应等于true。

如何构建查询以使用MongoDB实现此类行为? 是否认为在插入时预先计算某些值是一种好习惯,而不是在获取请求期间计算它们?

1 个答案:

答案 0 :(得分:1)

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"肯定有"最高日期推进"。

与您要求的第二个问题相关,您可以遵循类似的策略。仅在{"allAre": false}时更新{"_id":yourID, "items.is":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) {
   }
  );