Сводные документы в MongoDB двойных вложенных массивов - PullRequest
0 голосов
/ 09 декабря 2018

Я пытаюсь считать документы с разными условиями.Здесь у меня есть такая упрощенная таблица текстов (документов):

{ 
  "teamId": "1",
  "stage": "0",
  "answeredBy": [userId_1, userId_2],
  "skippedBy": [userId_3],
  "answers": []
},
{ 
  "teamId": "1",
  "stage": "0",
  "answeredBy": [userId_2],
  "skippedBy": [userId_1],
  "answers": []
},
{ 
  "teamId" : "1",
  "stage": "0",
  "answeredBy": [userId_3],
  "skippedBy": [userId_2],
  "answers": []
},
{ 
  "teamId" : "1",
  "stage": "1",
  "answeredBy": [userId_3],
  "skippedBy": [userId_1, userId_2],
  "answers": [
              { "readBy": [userId_1] },
              { "readBy": [userId_1, userId_2] },
              { "readBy": [userId_3, userId_1] },       
  ]
},
{ 
  "teamId" : "1",
  "stage": "1",
  "answeredBy": [userId_3],
  "skippedBy": [userId_1, userId_2],
  "answers": [
              { "readBy": [userId_1] },
              { "readBy": [userId_1, userId_2] },
              { "readBy": [userId_3] },       
  ]
};

И я хочу подсчитать в одном запросе для каждого соответствующего идентификатора пользователя, этапа и teamID (поэтому первый $ match должен быть для каждого идентификатора команды и этапов: "0 "или" 1 ":

  • сколько документов на этапе:" 0 "содержит идентификатор пользователя в массивах answerBy ИЛИ skippedBy (я назвал этот документ" отвеченным ")
  • сколько документов на этапе: «0» не содержит ИД пользователя как в массивах answerBy, так и в skippedBy (я назвал этот документ «неотвеченным»)
  • сколькодокументы со стадией: «1» имеют в массиве ответов, по крайней мере, ОДИН массив readBy, который не содержит пользователя (я назвал его «UnRead» документом)

Поэтому я попытался добиться этого вЕсть много способов, но самая сложная часть - перебрать вложенные массивы ( readBy ) массива ответов и найти, какой из них не содержит соответствующего пользователя, и посчитать этот документ как UNREAD .

Возможные результаты:

 {
   answered: 2,
   unanswered: 1,
   unread: 1,
 };

или

 [
   { _id: 'answered', count: 2 },
   { _id: 'unanswered', count: 1 },
   { _id: 'unread', count: 1 }
 ]

Я застрял после написания этого запроса и не знаю, как перебирать массивы readBy:

db.texts.aggregate([
      { $match: {teamId: 1, $or: [{currStage: 0}, {currStage: 1}]}},
      { $project: { 'stage': { $switch: { branches: [
      { case: 
             { $and: [ { $eq: [ '$currStage', 0 ] },
             { $not: [ { $or: [ { $in: [ userId_1, '$answeredBy' ] },
             { $in: [ userId_1, '$skippedBy' ] } ] } ] } ] },
        then: 'unanswered'},
      { case: 
             { $and: [ { $eq: [ '$currStage', 0 ] },
             { $or: [ { $in: [ userId_1, '$answeredBy' ] },
             { $in: [ userId_1, '$skippedBy' ] } ] } ] },
        then: 'answered'},
      { case:
             { $and: [ { $eq: [ '$currStage', 1 ] },
             { $not: [ { $in: [ userId_1, '$answers.readBy' ] } ] } ] },
        then: 'unread'},
                 ] } } } },
      { $group: { _id: '$stage', count: { $sum: 1 } } },
 ]); 

Ответы [ 2 ]

0 голосов
/ 12 декабря 2018

Вот мое рабочее решение.Спасибо всем, кто пытался ее решить и помог мне.

db.test.aggregate([
  { $match: {teamId: "1", $or: [{stage: "0"}, {stage: "1", "answers": {$elemMatch: {"readBy": {$nin: ["userId_1"]}}}}]}},
  { $project: { 'stage': { $switch: { branches: [
  { case: 
         { $and: [ { $eq: [ '$stage', "0" ] },
         { $not: [ { $or: [ { $in: [ "userId_1", '$answeredBy' ] },
         { $in: [ "userId_1", '$skippedBy' ] } ] } ] } ] },
    then: 'unanswered'},
  { case: 
         { $and: [ { $eq: [ '$stage', "0" ] },
         { $or: [ { $in: [ "userId_1", '$answeredBy' ] },
         { $in: [ "userId_1", '$skippedBy' ] } ] } ] },
    then: 'answered'},
  { case:
         { $eq: [ '$stage', "1" ] } ,
    then: 'unread'},
             ] } } } },
  { $group: { _id: '$stage', count: { $sum: 1 } } },
])

Возможно, мне стоит найти лучшее решение, но сейчас это то, что мне нужно.

0 голосов
/ 10 декабря 2018

попробуйте это, я предполагаю userid = userId_1

db.getCollection('answers').aggregate([
      { $match: {teamId: '1', $or: [{stage: '0'}, {stage: '1'}]}},
      {$project:{
          counts :{$cond: [
              {$or:[{$in:["userId_1", "$answeredBy"]}, {$in:["userId_1", "$skippedBy"]}]}, 
              {$literal:{answered: 1, unaswered: 0}}, 
              {$literal:{answered: 0, unaswered: 1}}
          ]},
          unread : {$cond:[
                  {$gt:[{$reduce: {
                      input: "$answers", 
                      initialValue: 1, 
                      in: {$multiply:["$$value", 
                          {$cond:[
                              {$in:["userId_1", "$$this.readBy"]},
                              {$literal: 0},
                              {$literal: 1}
                           ]}
                       ]}}},
                       0
                     ]},
                     {$literal: 1},
                     {$literal: 0}
               ]}

      }},
      {$group: {_id: null, answered: {$sum: "$counts.answered"}, unanswered: {$sum: "$counts.unanswered"}, unread: {$sum: "$unread"}}}
])
...