【问题标题】:Filter nested array with conditions based on multi-level object values and update them - MongoDB aggregate + update根据多级对象值过滤嵌套数组并更新它们 - MongoDB聚合+更新
【发布时间】:2020-07-24 05:21:42
【问题描述】:

考虑到我在一个集合中有以下文档(忽略_id

[
  {
    "Id": "OP01",
    "Sessions": [
      {
        "Id": "Session01",
        "Conversations": [
          {
            "Id": "Conversation01",
            "Messages": [
              {
                "Id": "Message01",
                "Status": "read",
                "Direction": "inbound"
              },
              {
                "Id": "Message02",
                "Status": "delivered",
                "Direction": "internal"
              },
              {
                "Id": "Message03",
                "Status": "delivered",
                "Direction": "inbound"
              },
              {
                "Id": "Message04",
                "Status": "sent",
                "Direction": "outbound"
              }
            ]
          },
          {
            "Id": "Conversation02",
            "Messages": [
              {
                "Id": "Message05",
                "Status": "sent",
                "Direction": "outbound"
              }
            ]
          }
        ]
      },
      {
        "Id": "Session02",
        "Conversations": [
          {
            "Id": "Conversation03",
            "Messages": [
              {
                "Id": "Message06",
                "Status": "read",
                "Direction": "inbound"
              },
              {
                "Id": "Message07",
                "Status": "delivered",
                "Direction": "internal"
              }
            ]
          },
          {
            "Id": "Conversation04",
            "Messages": []
          }
        ]
      }
    ]
  },
  {
    "Id": "OP02",
    "Sessions": [
      {
        "Id": "Session03",
        "Conversations": []
      }
    ]
  },
  {
    "Id": "OP03",
    "Sessions": []
  }
]

第一个查询 - 聚合 (+$project)

我想获取按他们的 Conversations 分组的 Messages 列表,其中:

  • Sessions.Id: "Session01"

  • Sessions.Conversations.Messages.Direction $in ["inbound", "outbound"]

  • Sessions.Conversations.Messages.Status $in ["sent", "delivered"]

预期结果是:

[
  {
    "Id": "Conversation01",
    "Messages": [
      {
        "Id": "Message03",
        "Status": "delivered",
        "Direction": "inbound"
      },
      {
        "Id": "Message04",
        "Status": "sent",
        "Direction": "outbound"
      }
    ]
  },
  {
    "Id": "Conversation02",
    "Messages": [
      {
        "Id": "Message05",
        "Status": "sent",
        "Direction": "outbound"
      }
    ]
  }
]

附注:

如果在不同的documents(或不同的Sessions)上验证Sessions.Id: "Session01"条件("Session01"不是唯一键),document' s Messages 符合其他条件的也应该添加。

结果输出未提及documentSessions 级别。


第二个查询——更新

我想将所有这些消息中的Sessions.Conversations.Messages.Status(与以前相同)更新为"read"

该集合现在应该具有以下文档:

请注意以下更改:

  • Sessions.Conversations.Messages.Id = "Message03"
  • Sessions.Conversations.Messages.Id = "Message04"
  • Sessions.Conversations.Messages.Id = "Message05"

Sessions.Id = "Session01"

[
  {
    "Id": "OP01",
    "Sessions": [
      {
        "Id": "Session01",
        "Conversations": [
          {
            "Id": "Conversation01",
            "Messages": [
              {
                "Id": "Message01",
                "Status": "read",
                "Direction": "inbound"
              },
              {
                "Id": "Message02",
                "Status": "delivered",
                "Direction": "internal"
              },
              {
                "Id": "Message03",
                "Status": "read",
                "Direction": "inbound"
              },
              {
                "Id": "Message04",
                "Status": "read",
                "Direction": "outbound"
              }
            ]
          },
          {
            "Id": "Conversation02",
            "Messages": [
              {
                "Id": "Message05",
                "Status": "read",
                "Direction": "outbound"
              }
            ]
          }
        ]
      },
      {
        "Id": "Session02",
        "Conversations": [
          {
            "Id": "Conversation03",
            "Messages": [
              {
                "Id": "Message06",
                "Status": "read",
                "Direction": "inbound"
              },
              {
                "Id": "Message07",
                "Status": "delivered",
                "Direction": "internal"
              }
            ]
          },
          {
            "Id": "Conversation04",
            "Messages": []
          }
        ]
      }
    ]
  },
  {
    "Id": "OP02",
    "Sessions": [
      {
        "Id": "Session03",
        "Conversations": []
      }
    ]
  },
  {
    "Id": "OP03",
    "Sessions": []
  }
]

如何使用 aggregateupdate_one 查询来完成这些结果?


以下是两个查询的直观解释:

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework aggregate pymongo


    【解决方案1】:

    我已经写了聚合查询

            db.session.aggregate([
              {
                $unwind:"$Sessions"
              },
              {
                $unwind:"$Sessions.Conversations"
              },
              {
                $unwind:"$Sessions.Conversations.Messages"
              },
              {
                $match:{
                  "Sessions.Id" : "Session01",
                  "Sessions.Conversations.Messages.Direction":{
                    $in:[
                      "inbound", "outbound"
                    ]
                  },
                  "Sessions.Conversations.Messages.Status":{
                    $in:[
                      "sent", "delivered" 
                    ]
                  }
                }
              },
              {
                $group:{
                  "_id":"$Sessions.Conversations.Id",
                  "Messages":{
                    $push:"$Sessions.Conversations.Messages"
                  }
                }
              }
            ]).pretty()
    

    输出

            {
                    "_id" : "Conversation02",
                    "Messages" : [
                            {
                                    "Id" : "Message05",
                                    "Status" : "sent",
                                    "Direction" : "outbound"
                            }
                    ]
            }
            {
                    "_id" : "Conversation01",
                    "Messages" : [
                            {
                                    "Id" : "Message03",
                                    "Status" : "delivered",
                                    "Direction" : "inbound"
                            },
                            {
                                    "Id" : "Message04",
                                    "Status" : "sent",
                                    "Direction" : "outbound"
                            }
                    ]
            }
    

    现在更新文档:

    我用过positional-filters

            db.session.update(
              {},
              {
                $set:{
                  "Sessions.$[session].Conversations.$[].Messages.$[message].Status":"read"
                }
              },
              {
                "arrayFilters": [{"session.Id":"Session01"},{ "message.Id": "Message05" }] 
              }
            )
    

    这会将"session.Id":"Session01""message.Id": "Message05" 的状态更新为read

    希望这会对您有所帮助。 :)

    更新

            db.session.update(
              {},
              {
                $set:{
                  "Sessions.$[session].Conversations.$[].Messages.$[message].Status":"read"
                }
              },
              {
                "arrayFilters": [
                  {
                    "session.Id":"Session01"
                  },
                  { 
                    "message.Direction": {
                      $in :[
                        "inbound", 
                        "outbound"
                      ]
                    },
                    "message.Status": {
                      $in :[
                        "sent", 
                        "delivered"
                      ]
                    }
                  }
                ] 
              }
            )
    

    【讨论】:

    • 是的,这是可能的。我已经根据聚合过滤器更新了我的答案。
    • 很高兴它对你有所帮助 :)
    • 实施您的解决方案我发现了一个新问题:在$group 中,我无法添加更多字段,例如"_id":"$Sessions.Conversations.Id"。假设Sessions.Conversation 还有一个键"Info",它是一个对象。我不能写 info: "$Sessions.Conversations.Info" - 结果: The field 'info' must be an accumulator object
    • 您需要在_id 中添加一个对象 例如:``` {$group:{"_id":{"Id":"$Sessions.Conversation.Id","info": "$Sessions.Conversation.info"}}}```
    • 我用"info":{"$first":"$Sessions.Conversation.info"}修复了它
    猜你喜欢
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-13
    • 1970-01-01
    • 1970-01-01
    • 2021-11-29
    相关资源
    最近更新 更多