Фильтрация вложенного массива с условиями на основе значений многоуровневых объектов и их обновление - MongoDB aggregate + update - PullRequest
1 голос
/ 11 апреля 2020

Учитывая, что у меня есть следующие документы в коллекции (игнорируя _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)

Я хочу получить список Messages, сгруппированный по их Conversations, где:

  • 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 Messages, которые соответствуют другим условиям, также должны быть добавлены.

Вывод результатов не включает ни document, ни Sessions уровни.


Второй запрос - обновить

Я хочу обновить Sessions.Conversations.Messages.Status всех этих сообщений (то же самое) состояние как и раньше) до "read".

Теперь в коллекции должны быть следующие документы:

Обратите внимание на изменения:

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

at 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": []
  }
]

Как мне выполнить sh эти результаты с aggregate и update_one запросами?


Вот визуальное объяснение обоих запросов:

Explanation of queries

1 Ответ

1 голос
/ 13 апреля 2020

Я написал запрос агрегации

        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"
                        }
                ]
        }

Теперь для обновления документа:

Я использовал позиционные фильтры

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

Это обновит статус как read для "session.Id":"Session01" и "message.Id": "Message05"

Надеюсь, это поможет вам. :)

ОБНОВЛЕНИЕ

        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"
                  ]
                }
              }
            ] 
          }
        )
...