mongodb聚合根据数组中的值条件添加字段

问题描述 投票:0回答:1

请原谅标题。可以找到更好的描述来描述我正在尝试做的事情。

我有一个消息集合,其中存储以下信息

  • code:消息的唯一识别码
  • 发件人:发送消息的电话号码
  • to:消息发送到的电话号码
  • 消息:消息文本
  • readings:ObjectId 数组。另一个集合中的 ids 参考文档名为“users”。如果此处有 ObjectId,则表示该消息已被该特定用户读取。

示例数据

{
    "_id" : ObjectId("59ba30c95869d32a803e4c4d"),
    "code" : "SM54c9366e9b8544e89bdcf2ee841adea7",
    "from" : "+49157xxxxxxx",
    "to" : "+49160xxxxxxxx",
    "message" : "xxxxxxxx",
    "createdAt" : ISODate("2017-09-14T07:33:39.000Z"),
    "lastModifiedAt" : ISODate("2017-09-14T07:33:32.324Z"),
    "status" : "delivered",
    "room" : ObjectId("59bfa293bd7717251cecfae7"),
    "readings" : [ 
        ObjectId("59c25751dcfdaf2944ee2fae"), 
        ObjectId("59c25751dcfdaf2944e32fae")
    ],
}

/* 2 */
{
    "_id" : ObjectId("59ba3270f53b7f2fb4fa807f"),
    "code" : "SM04585672d02644018e3ff466d73c571d",
    "from" : "+49xxxxxxx",
    "to" : "+49xxxxxxxx",
    "message" : "xxxxxxx",
    "createdAt" : ISODate("2017-09-14T07:40:42.000Z"),
    "lastModifiedAt" : ISODate("2017-09-14T07:40:34.338Z"),
    "status" : "delivered",
    "room" : ObjectId("59bfa293bd7717251cecfae7"),
    "readings" : [ 
        ObjectId("59c25751dcfdaf2944ee2fae")
    ],
}

我想要实现的是,如果特定用户已阅读该消息,则该消息会获得一个附加字段“hasRead”。

这是我想要达到的结果

{
    "_id" : ObjectId("59ba30c95869d32a803e4c4d"),
    "code" : "SM54c9366e9b8544e89bdcf2ee841adea7",
    "to" : "+491606983534",
    "message" : "Schau mer mal",
    "createdAt" : ISODate("2017-09-14T07:33:39.000Z"),
    "lastModifiedAt" : ISODate("2017-09-14T07:33:32.324Z"),
    "status" : "delivered",
    "room" : ObjectId("59bfa293bd7717251cecfae7"),
    "hasRead" : true
}

/* 2 */
{
    "_id" : ObjectId("59ba3270f53b7f2fb4fa807f"),
    "code" : "SM04585672d02644018e3ff466d73c571d",
    "to" : "+491606983534",
    "message" : "Schau mer mal",
    "createdAt" : ISODate("2017-09-14T07:40:42.000Z"),
    "lastModifiedAt" : ISODate("2017-09-14T07:40:34.338Z"),
    "status" : "delivered",
    "room" : ObjectId("59bfa293bd7717251cecfae7"),
    "hasRead" : true
}

我构建了一个包含以下阶段的聚合,但对于这样一个简单的任务来说,它看起来太大了,我想知道是否有一种更优雅、更轻松的方法来做到这一点?

阶段是:

  • $addFields:检查读数数组是否为 0。如果为 0,则添加一个虚拟 ObjectId,否则设置读数数组
  • $unwind:展开读数数组
  • $addFields:在检查特定 ObjectId 是否与“readings”字段匹配时添加字段“hasRead”。如果相等则为真,否则为假
  • $group:按除“hasRead”字段之外的所有字段进行分组,“hasRead”基于 $max hasRead
  • $project:构造结果以使其成为平面对象。

这是我的代码:

db.getCollection('sms').aggregate([
{ $addFields: {
    "readings": {
        "$cond": {
            if: { $or: [ { "$gt": [ {"$size": "$readings"},0] } ]} ,
            then: "$readings",
            else: [ObjectId("000000000000000000000000")]
        }
    }
}},
{ $unwind: "$readings" },
{ $addFields: { 
    "hasRead": { 
        $cond: { 
            if: { 
                $eq: ["$readings", ObjectId("59c25751dcfdaf2944ee2fae")] 
            }, 
            then: true, 
            else: false 
        }
    } 
  } 
},
{ $group: {
    _id: { 
        _id: "$_id",
        code: "$code",
        from: "$from",
        to: "$to",
        message: "$message",
        createdAt: "$createdAt",
        lastModifiedAt: "$lastModifiedAt",
        room: "$room"
    },
    hasRead: { $max: "$hasRead" }
}},

{ $project: {
    "_id": "$_id._id",
    "code": "$_id.code",
    "from": "$_id.from",
    "to": "$_id.to",
    "message": "$_id.message",
    "createdAt": "$_id.createdAt",
    "lastModifiedAt": "$_id.lastModifiedAt",
    "room": "$_id.room",
    "hasRead": "$hasRead"
}}
])

浏览完尼尔(参见评论)给出的另一个问题的答案后,我可以简化对此的查询:

db.getCollection('sms').aggregate([
    { "$addFields": {
        "hasRead" : {
            "$filter": {
                "input": { "$setUnion": [ "$readings", []] },
                "as": "o",
                "cond" : {
                    "$eq": [ "$$o",ObjectId("59c25751dcfdaf2944ee2fae")]
                    }
                }
            }
        }
    },
    { "$project": {
        "_id": 1,
        "code": 1,
        "to": 1,
        "message": 1,
        "createdAt": 1,
        "lastModifiedAt" : 1,
        "status": 1,
        "room": 1,
        "hasRead": { 
            "$cond": {
            if: { $or: [ { "$gt": [ {"$size": "$readings"},0] } ]} ,
            then: true,
            else: false
            }
        }
    }
}
])
mongodb mongodb-query aggregation-framework
1个回答
0
投票

太晚了,但你可以简单地写:

db.getCollection("sms").aggregate([
  {
    $project: {
      _id: 1,
      code: 1,
      to: 1,
      message: 1,
      createdAt: 1,
      lastModifiedAt: 1,
      status: 1,
      room: 1,
      hasRead: {
        $in: [ObjectId("59c25751dcfdaf2944ee2fae"), "$readings"],
      },
    },
  },
]);

通常最简单的解决方案就是正确的:)

© www.soinside.com 2019 - 2024. All rights reserved.