Использование чего-то вроде $ group внутри $ addFields - PullRequest
1 голос
/ 13 апреля 2020

Ниже приведен один из моих документов из коллекции movies:

{
        "_id" : 4,
        "startYear" : 1892,
        "title" : "Un bon bock",
        "originalTitle" : "Un bon bock",
        "rating" : 6.4,
        "type" : "short",
        "numVotes" : 105,
        "genres" : [
                "Short",
                "Animation"
        ]
}

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

normalizedRating = (rating - min(rating)) / (max(rating) - min(rating))

Итак, я получаю документ как:

{
        "_id" : 4,
        "startYear" : 1892,
        "title" : "Un bon bock",
        "originalTitle" : "Un bon bock",
        "rating" : 6.4,
        "type" : "short",
        "numVotes" : 105,
        "genres" : [
                "Short",
                "Animation"
        ], 
        "normalizedRating": 6.3
}

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

1 Ответ

1 голос
/ 13 апреля 2020

Если вы хотите сделать это в одном запросе, попробуйте один из следующих двух:

Запрос 1:

db.collection.aggregate([
  {
    $group: {
      _id: "",
      maxRating: { $max: "$rating" },
      minRating: { $min: "$rating" },
      data: { $push: "$$ROOT" },
    },
  },
  {
    $unwind: "$data",
  },
  {
    $addFields: {
      "data.normalizedRating": {
        $divide: [
          { $subtract: ["$data.rating", "$minRating"] },
          { $subtract: ["$maxRating", "$minRating"] },
        ],
      },
    },
  },
  {
    $replaceRoot: { newRoot: "$data" },
  },
]);

Тест: MongoDB-площадка

Запрос 2:

db.collection.aggregate([
  {
    $facet: {
      data: [{ $match: {} }],
      ratingValues: [
        {
          $group: {
            _id: "",
            maxRating: { $max: "$rating" },
            minRating: { $min: "$rating" },
          },
        },
      ],
    },
  },
  {
    $unwind: "$data",
  },
  {
    $unwind: "$ratingValues",
  },
  {
    $addFields: {
      "data.normalizedRating": {
        $divide: [
          { $subtract: ["$data.rating", "$ratingValues.minRating"] },
          { $subtract: ["$ratingValues.maxRating", "$ratingValues.minRating"] },
        ],
      },
    },
  },
  {
    $project: { ratingValues: 0 },
  },
  {
    $replaceRoot: { newRoot: "$data" },
  },
]);

Тест: MongoDB-площадка

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

...