MongoDB пишет запрос для вычисления процентного изменения - PullRequest
1 голос
/ 07 мая 2020

Я новичок в написании запросов в MongoDB.

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

Предыдущие рейтинги хранятся в поле «changelog», а самые последние предыдущие рейтинги находятся в последнем индексе массива «changelog».

Вот как выглядит коллекция:

"changelog": [{
        --Earliest Version--
        "Title": "Foo",
        "Director": "Bar",
        "Genre": "Action",
        "rating": {
            "$numberDouble": "3.45"
            }
        }, 
        {
        --Most recent previous version of this movie, the one I want--
        "Title": "Foo",
        "Director": "Bar",
        "Genre": "Action",
        "rating": {
            "$numberDouble": "4.96"
            }
        }],

--here is current movie info--
"Title": "Foo",
"Director": "Bar",
"Genre": "Action",
"rating": {
    "$numberDouble": "4.99"
    }

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

Моя проблема связана с доступом к последней оценке в массиве журнала изменений. Ошибка: «Невозможно вычесть двойное число по массиву», поэтому "$last_changelog.rating" возвращает массив с одним элементом, но я не знаю, как просто получить само двойное число.

db.collection.aggregate(
[
    {"$project": {
      "_id": 1,
      "rating": true,
      "changelog": true,
      "last_changelog": {"$slice": ["$changelog", -1]}
        }
    },
    {"$project":{
        "_id":"$_id", 
        "rating": "$rating",
        "percent_change": {

            # more arithmetic is needed
            "$subtract": ["$rating", "$last_changelog.rating"]}, # error is here, doesn't get correct previous rating value.
        }
    },
    {"$sort": {"percent_change": -1}},
])

ПРИМЕЧАНИЕ. Мне нужно использовать здесь aggregate (), потому что я работаю в программе визуализации Metabase, и это единственный запрос, который они поддерживают. Спасибо за помощь!

1 Ответ

0 голосов
/ 07 мая 2020

Вы можете попробовать следующий запрос агрегирования:

db.collection.aggregate([
    /** Create a new field `changePercent` which is `rating of lastElem - rating of secondFromLastElem %` 
     * `$slice` will give you rating value in an array, using `$arrayElemAt` to convert value in array to a value
     */
    {
      $addFields: { changePercent: { $subtract: [ { $arrayElemAt: [ { $slice: [ "$changelog.rating", -1 ] }, 0 ] }, { $arrayElemAt: [ { $slice: [ "$changelog.rating", -2 ] }, 0 ] } ] } }
    },
    /** sort on new field in descending order */
    {
      $sort: { changePercent: -1 }
    },
    /** Remove newly create field from output */
    {
      $project: { changePercent: 0 }
    }
  ])

Тест: mongoplayground

Обновление: Вместо используя $slice, вы можете просто использовать $arrayElemAt. Единственное отличие будет заключаться в том, что в массиве changelog есть только один элемент, тогда $arrayElemAt ничего не вернет в -2, что делает $subtract return null в поле changePercent - не должно быть, если вы хотите показать в ответ поле changePercent. Где as $slice вернет тот же элемент даже с -1 или -2 для одного элемента в массиве changelog, что приведет к changePercent : 0 хорошо, если вы хотите, чтобы значение было в ответе:

db.collection.aggregate([
    {
      $addFields: { changePercent: { $subtract: [ { $arrayElemAt: [ "$changelog.rating", -1 ] }, { $arrayElemAt: [ "$changelog.rating", -2 ] } ] } }
    },
    {
      $sort: { changePercent: -1 }
    },
    {
      $project: { changePercent: 0 }
    }
  ])

Тест: mongoplayground

Ссылка: конвейер агрегации

...