【问题标题】:Query to update an array field by using another array field of same document in mongodb在 mongodb 中使用同一文档的另一个数组字段查询以更新数组字段
【发布时间】:2021-07-01 03:46:23
【问题描述】:

场景

我有以下来自Chat 集合的文档,其中包含messages 和members 的数组。

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

{
    "_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 数组并将其插入到 messages 的 status 字段中

MongoDB 版本: 4.0.5

【问题讨论】:

  • 您好,您能否详细说明这一点“为每个成员(发件人除外)插入上述json”。比如你如何识别chats集合中的发件人?

标签: arrays mongodb nested mongodb-query


【解决方案1】:

演示 - 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 以提高性能

【讨论】:

  • 我可以在没有$[] 的情况下做到这一点。 mongoplayground.net/p/LgVPfRoXL5p。只需要直接从members 字段映射状态数组。这就是我卡住的地方。一种方法是先获取成员,然后将其映射到服务器端,然后将其插入数据库。但这可以在一个查询中完成吗?
【解决方案2】:

您可以使用$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" : [ ]
        }
    ]
}

【讨论】:

  • 它会起作用,但我想为聊天的每个成员执行它,如果它有 100 个成员怎么办?
  • 不,我的意思是我只想映射members 数组并将其插入status。这让你的问题清楚了吗?
  • 你的 MongoDB 版本是多少?
  • MongoDB版本为4.0.5
  • 检查更新的答案,如果你升级你的 MongoDB。
猜你喜欢
  • 2018-12-08
  • 2013-06-14
  • 1970-01-01
  • 2020-07-29
  • 2020-07-31
  • 2021-07-20
  • 1970-01-01
  • 2019-02-13
  • 1970-01-01
相关资源
最近更新 更多