#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:
- Пример существующего conf/user/br-сеанса : Тестовый код здесь
- В случае существующей конф/пользователя/без-бр-сессии : Тестовый код здесь
- Случай существующей конф/нового пользователя : Тестовый код здесь
- Case new conf (так же новый пользователь) : Тестовый код здесь
Запрос
- первый фильтр/
$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. Это отличная работа. Спасибо