查询以使用 mongodb 中同一文档的另一个数组字段更新数组字段

时间:2021-04-05 08:45:01

标签: arrays mongodb nested mongodb-query

场景

我在聊天中有 Chat 集合中的以下文档,其中包含 messagesmembers 数组。

对于每条消息,都会有一个状态字段,用于存储关于用户的发送和读取时间戳。

{
    "_id" : ObjectId("60679797b4365465745065b2"),
    "members" : [ 
        ObjectId("604e02033f4fc07b6b82771c"), 
        ObjectId("6056ef4630d7b103d8043abd"), 
        ObjectId("6031e3dce8934f11f8c9a79c")
    ],
    "isGroup" : true,
    "createdAt" : 1617401743720.0,
    "updatedAt" : 1617436504453.0,
    "messages" : [ 
        {
            "createdAt" : 1617401743719.0,
            "updatedAt" : 1617401743719.0,
            "_id" : ObjectId("60679797b4365465745065b3"),
            "body" : "This is test message",
            "senderId" : ObjectId("6031e3dce8934f11f8c9a79c"),
            "status" : []
        }
    ]
}

因此,我想将以下数据插入到 messages.status 数组中,以了解成员何时接收/读取消息。

{
    receiverId: <member of chat>
    deliveredAt: <timestamp>
    readAt: <timestamp>
}

问题

如何编写查询,通过使用现有字段中的数据,为status数组中的每个成员(发件人除外)插入上述json?

这样,在查询之后,文档应该是这样的:

{
    "_id" : ObjectId("60679797b4365465745065b2"),
    "members" : [ 
        ObjectId("604e02033f4fc07b6b82771c"), 
        ObjectId("6056ef4630d7b103d8043abd"), 
        ObjectId("6031e3dce8934f11f8c9a79c")
    ],
    "isGroup" : true,
    "createdAt" : 1617401743720.0,
    "updatedAt" : 1617436504453.0,
    "messages" : [ 
        {
            "createdAt" : 1617401743719.0,
            "updatedAt" : 1617401743719.0,
            "_id" : ObjectId("60679797b4365465745065b3"),
            "body" : "This is test message",
            "senderId" : ObjectId("6031e3dce8934f11f8c9a79c"),
            "status" : [{
                "receiverId": ObjectId("604e02033f4fc07b6b82771c")
                "deliveredAt": <timestamp>
                "readAt": <timestamp>
            }, {
                "receiverId": ObjectId("6056ef4630d7b103d8043abd")
                "deliveredAt": <timestamp>
                "readAt": <timestamp>
            }]
        }
    ]
}

编辑

我可以对静态数据执行此操作。

链接:https://mongoplayground.net/p/LgVPfRoXL5p

为了便于理解:我必须映射 members 数组并将其插入到 statusmessages 字段

MongoDB 版本: 4.0.5

2 个答案:

答案 0 :(得分:1)

您可以使用 $function 运算符定义自定义函数以实现 MongoDB 查询语言不支持的行为。因此,与 updates-with-aggregate-pipeline$function 一起,您可以仅使用接收者的详细信息更新 messages.status 数组,如下所示:

注意:仅适用于 MongoDB 版本 >= 4.4。

试试这个:

let messageId = ObjectId("60679797b4365465745065b3");

db.chats.update(
  { "messages._id": messageId },
  [
    {
      $set: {
        "messages": {
          $map: {
            input: "$messages",
            as: "message",
            in: {
              $cond: {
                if: { $eq: ["$$message._id", messageId] },
                then: {
                  $function: {
                    body: function (message, members) {
                      message.status = [];
                      for (let i = 0; i < members.length; i++) {
                        if (message.senderId.valueOf() != members[i].valueOf()) {
                          message.status.push({
                            receiverId: members[i],
                            deliveredAt: new Date().getTime(),
                            readAt: new Date().getTime()
                          })
                        }
                      }

                      return message;
                    },
                    args: ["$$message", "$members"],
                    lang: "js"
                  }
                },
                else: "$$message"
              }
            }
          }
        }
      }
    }
  ]
);

输出:

{
    "_id" : ObjectId("60679797b4365465745065b2"),
    "members" : [
        ObjectId("604e02033f4fc07b6b82771c"),
        ObjectId("6056ef4630d7b103d8043abd"),
        ObjectId("6031e3dce8934f11f8c9a79c")
    ],
    "isGroup" : true,
    "createdAt" : 1617401743720,
    "updatedAt" : 1617436504453,
    "messages" : [
        {
            "_id" : ObjectId("60679797b4365465745065b3"),
            "createdAt" : 1617401743719,
            "updatedAt" : 1617401743719,
            "body" : "This is test message",
            "senderId" : ObjectId("6031e3dce8934f11f8c9a79c"),
            "status" : [
                {
                    "receiverId" : ObjectId("604e02033f4fc07b6b82771c"),
                    "deliveredAt" : 1617625735318,
                    "readAt" : 1617625735318
                },
                {
                    "receiverId" : ObjectId("6056ef4630d7b103d8043abd"),
                    "deliveredAt" : 1617625735318,
                    "readAt" : 1617625735318
                }
            ]
        },
        {
            "_id" : ObjectId("60679797b4365465745065b4"),
            "createdAt" : 1617401743719,
            "updatedAt" : 1617401743719,
            "body" : "This is test message",
            "senderId" : ObjectId("6031e3dce8934f11f8c9a79d"),
            "status" : [ ]
        }
    ]
}

答案 1 :(得分:0)

演示 - https://mongoplayground.net/p/FoOvxXp6nji

https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/

<块引用>

过滤后的位置运算符 $[] 标识与更新操作的 arrayFilters 条件匹配的数组元素,例如

db.collection.update({
  "messages.senderId": "6031e3dce8934f11f8c9a79c" // query 
},
{
  "$push": {
    "messages.$[m].status": [ // push into the matching element of arrayFilters
      {
        "receiverId": ObjectId("604e02033f4fc07b6b82771c")
      },
      {
        "receiverId": ObjectId("6056ef4630d7b103d8043abd")
      }
    ]
  }
},
{
  arrayFilters: [
    {
      "m.senderId": "6031e3dce8934f11f8c9a79c" // matches array element where senderId is 6031e3dce8934f11f8c9a79c
    }
  ]
})

注意 - 将索引添加到 messages.senderId 以提高性能

相关问题