Агрегация MongoDb: как я могу сгруппировать массив-1 на основе другого массива-2, когда заданы массивы-1 и массив-2? - PullRequest
1 голос
/ 13 июля 2020

РЕДАКТИРОВАТЬ: Мой исходный вопрос был

MongoDb Aggregation: Можете ли вы $ развернуть переменную входного документа в конвейере стадии поиска $?

Рассмотрите код ниже:

{$lookup: {
    from:"mydoc", 
    let: {"c":"$myArray"}, 
    pipeline: [ 
        {$unwind: "$$c"},
    ]
    as:"myNewDoc"
 }}

Как бы мне раскрутить c, если бы я хотел?

///// КОНЕЦ ОРИГИНАЛЬНОГО ВОПРОСА

--- --EDIT -----

Из комментария Тома Слаббэрта мы теперь знаем, что можно $ размотать переменную входного документа в конвейере стадии поиска $. Но это не рекомендуется.

Чего я пытаюсь достичь?

Рассмотрим эти коллекции, poll и castedvote из этот ответ из вопрос, который я задал .

Я пытаюсь получить результат, как показано ниже:

numberOfVotes: 6,
hasThisUserVoted: true,
numberOfComments: 12,
castedVotesPerChoice:{
    "choiceA": [
        {"_id": ObjectId("..."), "voter": "Juzi", "choice": 0, "pollId": 100 },
        {"_id": ObjectId("..."), "voter": "Juma", "choice": 0, "pollId": 100 },
        {"_id": ObjectId("..."), "voter": "Jane", "choice": 0, "pollId": 100 },
    ],
    "choiceB": [
        {"_id": ObjectId("..."), "voter": "Jamo", "choice": 1, "pollId": 100 },
        {"_id": ObjectId("..."), "voter": "Juju", "choice": 1, "pollId": 100 },
        {"_id": ObjectId("..."), "voter": "Jana", "choice": 1, "pollId": 100 }
    ],
    "choiceC": [ ]
}

моя текущая реализация:

db.poll.aggregate([
    {"$match": {"_id": 100}}, 
    // ...lookup to get comments
    {"$lookup": {
        "from":"castedvotes", 
        "let": {"pollId":"$_id"}, 
        "pipeline":[
            {"$match":
                {"$expr":
                    {"$eq": ["$pollId", "$$pollId"]},
            }},
        ], 
        "as":"votes" // will use this to get number of votes and find out if the authenticated user has voted.
    }},
    {"$unwind":"$choices"},
    {"$lookup": {
        "from":"castedvotes", 
        "let": {"c":"$choices"}, 
        "pipeline":[
            {"$match":
                {"$expr":
                    {"$eq": ["$choice", "$$c.id"]},
            }},
        ], 
        "as":"votesPerChoice"
    }},
])

Проблема, с которой я столкнулся с моей текущей реализацией, заключается в том, что он дважды выполняет поиск в одной и той же коллекции. Я чувствую, что в этом нет необходимости, и это делает код не dry. С $unwind я знаю, что могу отменить $unwind, как описано здесь .

Итак, мой вопрос в том, как я могу получить желаемый результат с помощью одного поиска $ в собранной коллекции голосов? Поскольку оба поиска возвращают одни и те же данные.

Или, чтобы задать вопрос по-другому, как я могу сгруппировать массив-1 на основе другого массива-2 в агрегации mongodb, когда заданы массив-1 и массив-2?

Этот вопрос отвечает, как группировать массивы на основе другого массива в агрегации mongodb, определенным образом структурируя этап $lookup. Не отвечает на мой вопрос.

1 Ответ

1 голос
/ 14 июля 2020

Если я правильно понял сообщение "головоломка" (заголовок сообщения и EDIT - разные варианты использования), мы можем получить желаемый результат с помощью одного $lookup:

db.poll.aggregate([
  {
    "$match": {
      "_id": 100
    }
  },
  {
    "$lookup": {
      "from": "castedvotes",
      "localField": "pollId",
      "foreignField": "choices.id",
      "as": "voters"
    }
  },
  {
    $project: {
      numberOfVotes: {
        $size: "$voters"
      },
      hasThisUserVoted: {
        $in: [
          "$_id",
          "$voters.pollId"
        ]
      },
      /**How to calculate it?*/
      numberOfComments: {
        $multiply: [
          {
            $size: "$voters"
          },
          2
        ]
      },
      castedVotesPerChoice: {
        $arrayToObject: {
          $map: {
            input: "$choices",
            as: "choice",
            in: {
              k: "$$choice.name",
              v: {
                $filter: {
                  input: "$voters",
                  as: "voter",
                  cond: {
                    $eq: [
                      "$$voter.choice",
                      "$$choice.id"
                    ]
                  }
                }
              }
            }
          }
        }
      }
    }
  }
])

MongoPlayground

...