Пн go: добавить поля со счетчиком того, сколько раз появляется другое поле - PullRequest
1 голос
/ 18 января 2020

Я новичок в MongoDB. Я пишу приложение, используя мон goose и NodeJS. Я начинаю с этой коллекции:

[
  { name: "Joe", hobby: "Food"},
  { name: "Lyn", hobby: "Food"},
  { name: "Rex", hobby: "Play"},
  { name: "Rex", hobby: "Shop"},
  ...
]

И я хочу вывести подмножество документов с двумя новыми полями: nameCount, показывающее, сколько раз появляется значение имени документа, и hobbyCount, показывающее то же самое вещь для хобби документа:

[
  { name: "Joe", hobby: "Food", nameCount: 1, hobbyCount: 2 },
  { name: "Lyn", hobby: "Food", nameCount: 1, hobbyCount: 2 },
  { name: "Rex", hobby: "Play", nameCount: 2, hobbyCount: 1 },
  { name: "Rex", hobby: "Shop", nameCount: 2, hobbyCount: 1 }
]

Из моих исследований и размышлений я получил следующий запрос для работы, но он кажется чрезмерным, неэффективным и чрезмерно сложным.

db.members.aggregate([
  {$skip: 0},
  {$limit: 4},
  {
    $lookup: {
      from: "members",
      let: { name: "$name"},
      pipeline: [
        { $match: { $expr: { $eq: ["$name", "$$name"] } } },
        { $count: "count" }
      ],
      as: "nameCount"
    }
  },
  { $unwind: "$nameCount" },
  { $addFields: { nameCount: "$nameCount.count" } },
  {
    $lookup: {
      from: "members",
      let: { hobby: "$hobby"},
      pipeline: [
        { $match: { $expr: { $eq: ["$hobby", "$$hobby"] } } },
        { $count: "count" }
      ],
      as: "hobbyCount"
    }
  },
  { $unwind: "$hobbyCount" },
  { $addFields: { hobbyCount: "$hobbyCount.count" } }
]);

Пн go Детская площадка

Меня, в частности, беспокоит не только то, что запрос кажется чрезмерным, но и то, что я выполняю два новых поиска в запись, найденная во всей коллекции, когда, возможно, nameCount и hobbyCount могут быть скомпилированы в одном поиске.

Обновление

Валиджон опубликовал ответ, который заставил меня понять, что я упростил свой фактический проблема при попытке выложить минимум необходимого. На самом деле коллекция фильтруется (с помощью $ match, $ skip и $ take) перед первым поиском, который я опубликовал. В результате ответ Валижона на самом деле не работает для меня, хотя это отличный ответ на то, как я изначально поставил проблему. Извините, я обновляю OP

Смотрите игровую площадку

1 Ответ

1 голос
/ 19 января 2020

РЕДАКТИРОВАТЬ: Нам нужно использовать только 1 $lookup (мы сопоставляем и по имени, и по хобби) и считать nameCount и hobbyCount, применяя операторы $filter или $reduce

db.members.aggregate([
  {
    $skip: 1
  },
  {
    $limit: 2
  },
  {
    $lookup: {
      from: "members",
      let: {
        name: "$name",
        hobby: "$hobby"
      },
      pipeline: [
        {
          $match: {
            $expr: {
              $or: [
                {
                  $eq: [
                    "$name",
                    "$$name"
                  ]
                },
                {
                  $eq: [
                    "$hobby",
                    "$$hobby"
                  ]
                }
              ]
            }
          }
        }
      ],
      as: "count"
    }
  },
  {
    $project: {
      _id: 0,
      name: 1,
      hobby: 1,
      nameCount: {
        $reduce: {
          input: "$count",
          initialValue: 0,
          in: {
            $add: [
              "$$value",
              {
                $cond: [
                  {
                    $eq: [
                      "$name",
                      "$$this.name"
                    ]
                  },
                  1,
                  0
                ]
              }
            ]
          }
        }
      },
      hobbyCount: {
        $size: {
          $filter: {
            input: "$count",
            cond: {
              $eq: [
                "$hobby",
                "$$this.hobby"
              ]
            }
          }
        }
      }
    }
  }
])

MongoPlayground

...