обновление/обновление mongodb и вложенные массивы

#arrays #mongodb #upsert #mongodb-update

Вопрос:

У меня есть коллекция, содержащая показатели о конференциях и пользователях на моем веб-сайте, и я хотел бы хранить их по конференциям. В каждой конференции есть один или несколько пользователей, и у каждого пользователя есть один или несколько сеансов, и у каждого сеанса есть один или несколько показателей.

Вот пример документа конференции, который я хочу сохранить :

 {
    "conf":"conference12345",
    "users":[
        { //User 1
            "uid":"2dd8b4e3-9dcd-4da6-bc36-aa0988dc9642",
            "sessions":[
                [// User 1 => session 1
                    {
                        "ts": 1234567891,
                        "br":"Chrome 92",
                        "os":"Windows",
                    },
                    {
                        "ts": 1234567899,
                        "bw":100
                    }
                ],
                [// User 1 => session 2
                    {
                        "ts": 1234567900,
                        "br":"Chrome 92",
                        "os":"Windows",
                    },
                    {
                        "ts": 1234567950,
                        "bw":500
                    }
                ],
            ]
        },
        { //User 2
            "uid":"2dd8b4e3-9dcd-4da6-bc36-aa0988dc9666",
            "sessions":[
                [// User 2 => session 1
                    {
                        "ts": 1234567891,
                        "br":"Chrome 90",
                        "os":"Mac",
                    },
                    {
                        "ts": 1234567899,
                        "bw":100
                    }
                ]
            ]
        }
    ]
}
 

Я хочу сразу вставить новые данные, используя db.collection.update upsert опцию with. Но мне было трудно понять, как это сделать. Метрики должны быть добавлены в последний элемент массива «сеансы».

Вот пример данных, которые я хочу добавить :

 // New user. a new document should be created because it's a new conference.
{ 
        "conf": "conferenceXYZ",
        "uid": "1cd8b4e3-9dcd-4da6-bc36-aa0988dc9512",
        "metrics": {
                "ts": 1234567891,
                "br":"Chrome 90",
                "os":"Mac",
        }
}

// Existing user. metrics should be added to his last session
{ 
        "conf": "conference12345",
        "uid": "2dd8b4e3-9dcd-4da6-bc36-aa0988dc9642",
        "metrics": {
                "ts": 1234567891,
                "bw":356
        }
}

 

Я пытался использовать обновление с опцией upsert, но трудно найти недостающие части. Любая помощь будет очень признательна.

Ответ №1:

Запрос

  • первый фильтр/ $set заключается в том, чтобы поместить ваши данные
  • проверяет, не появился ли новый пользователь (его новый пользователь в случае, если upsert или пользователь не найден)
  • если новый пользователь нажимает на нового пользователя, другой находит пользователя и добавляет новый сеанс
 db.collection.update({
  "conf": "conference12345"
},
[
  {
    "$set": {
      "uid": "2dd8b4e3-9dcd-4da6-bc36-aa0988dc9642",
      "usession": {
        "ts": 1234567891,
        "bw": 356
      }
    }
  },
  {
    "$set": {
      "new-user": {
        "$eq": [
          {
            "$filter": {
              "input": {
                "$cond": [
                  "$users",
                  "$users",
                  []
                ]
              },
              "as": "u",
              "cond": {
                "$eq": [
                  "$u.uid",
                  "$uid"
                ]
              }
            }
          },
          []
        ]
      }
    }
  },
  {
    "$set": {
      "users": {
        "$cond": [
          "$new-user",
          {
            "$concatArrays": [
              {
                "$cond": [
                  {
                    "$isArray": [
                      "$users"
                    ]
                  },
                  "$users",
                  []
                ]
              },
              [
                {
                  "uid": "$uid",
                  "sessions": [
                    [
                      "$usession"
                    ]
                  ]
                }
              ]
            ]
          },
          {
            "$map": {
              "input": "$users",
              "as": "u",
              "in": {
                "$cond": [
                  {
                    "$eq": [
                      "$u.uid",
                      "$uid"
                    ]
                  },
                  {
                    "$mergeObjects": [
                      "$u",
                      {
                        "sessions": {
                          "$let": {
                            "vars": {
                              "last_index": {
                                "$subtract": [
                                  {
                                    "$size": "$u.sessions"
                                  },
                                  1
                                ]
                              }
                            },
                            "in": {
                              "$cond": [
                                {
                                  "$or": [
                                    "$usession.br",
                                    {
                                      "$eq": [
                                        "$last_index",
                                        -1
                                      ]
                                    }
                                  ]
                                },
                                {
                                  "$concatArrays": [
                                    "$u.sessions",
                                    [
                                      [
                                        "$usession"
                                      ]
                                    ]
                                  ]
                                },
                                {
                                  "$let": {
                                    "vars": {
                                      "last_session": {
                                        "$arrayElemAt": [
                                          "$u.sessions",
                                          "$last_index"
                                        ]
                                      }
                                    },
                                    "in": {
                                      "$concatArrays": [
                                        {
                                          "$slice": [
                                            "$u.sessions",
                                            0,
                                            "$last_index"
                                          ]
                                        },
                                        [
                                          {
                                            "$concatArrays": [
                                              "$last_session",
                                              [
                                                "$usession"
                                              ]
                                            ]
                                          }
                                        ]
                                      ]
                                    }
                                  }
                                }
                              ]
                            }
                          }
                        }
                      }
                    ]
                  },
                  "$u"
                ]
              }
            }
          }
        ]
      }
    }
  },
  {
    "$unset": [
      "uid",
      "usession",
      "new-user"
    ]
  }
],
{
  "upsert": true
})
 

Комментарии:

1. Спасибо за ваше предложение. Этот запрос следует слегка отредактировать, чтобы добавить метрики в последний элемент sessions массива. Новый элемент сеанса должен быть создан, если объект метрик содержит br os элементы и

2. приведенный выше запрос всегда добавляет новый объект метрик в массив сеансов. Он никогда не сливается с существующим метриком, вы также хотите обновить существующие показатели? на основании каких критерий? то же ts самое ? Лучше всего написать все случаи и то, что вы хотите, чтобы произошло в каждом случае, я написал случаи, которые рассматривает запрос, расширьте эти случаи, если у вас есть больше случаев.

3. Спасибо, что нашли время для рассмотрения этого вопроса. Вот моя модификация mongoplayground.net/p/ghiWD3Cm2wy . новая метрика должна входить в последний массив сеансов, если только метрика не содержит br , что означает, что в массиве сеансов должен быть создан новый массив

4. я добавил еще один случай, если br для создания нового массива еще нужно нажать его в последнем сеансе. надеюсь, на этот раз у вас получится, запрос большой, но его простой JSON затрудняет чтение, но все в порядке

5. Это отличная работа. Спасибо