Mongodb: сортировка по пользовательскому выражению

Как отсортировать результаты по пользовательскому выражению, которое я использую в find?

Коллекция содержит документы со следующими атрибутами, например:

{
    "_id" : ObjectId("5ef1cd704b35c6d6698f2050"),
    "Name" : "TD",
    "Date" : ISODate("2021-06-23T09:37:51.976Z"),
    "A" : "19.36",
    "B" : 2.04,
}

Я использую следующий запрос find, чтобы получить записи с Date с 01.01.2022, а соотношение между A и B меньше, чем 0.1:

db.getCollection('my_collection').find(
    {
            "experationDate" : 
            {
                    $gte: new ISODate("2022-01-01 00:00:00.000Z")
            },
            "$expr": 
            {
                "$lte": [ 
                            { "$divide": ["$A", "$B"] },
                            0.1
                        ] 
            }
            
    })

Теперь я не могу найти правильный способ отсортировать результаты по этому соотношению.


person Gal Dreiman    schedule 24.11.2020    source источник
comment
Для выполнения всех этих задач можно использовать запрос агрегации. Этап $addFields можно использовать для вычисления производного значения и $sort позволит вам отсортировать вычисленное значение.   -  person prasad_    schedule 24.11.2020


Ответы (1)


Вы можете использовать aggregate таким образом:

Найдите нужные документы с помощью $match, добавьте поле с именем ratio и используйте его для сортировки. И, наконец, не показано поле с использованием $project:

db.collection.aggregate([
  { "$match": {
      "Date": { "$gte": ISODate("2020-01-01") },
      "$expr": { "$lte": [ { "$divide": [ "$B", { "$toDouble": "$A" } ] }, 0.1 ] } }
  },
  {
    "$set": {
      "ratio": { "$divide": [ "$B", { "$toDouble": "$A" } ] }
    }
  },
  {
    "$sort": { "ratio": 1 }
  },
  {
    "$project": { "ratio": 0 }
  }
])

Пример здесь

Кстати, я использовал другие значения для получения результатов. Соотношение между 2,04 и 19,36 больше 0,1. Вы разделили A/B, но я думаю, что вы имеете в виду B/A.

Кстати, это не важно, вы можете изменить значения, но запрос все равно будет работать нормально.

Кроме того, возможно, это могло бы работать лучше. Это тот же запрос, но он может быть более эффективным (может быть, я не знаю), потому что не позволяет дважды делить каждое значение на коллекцию:

Сначала отфильтруйте по дате, затем добавьте поле ratio к каждому найденному документу (и таким образом не обязательно делить каждый документ). Другой фильтр, использующий соотношение, сортировку и не выходное поле.

db.collection.aggregate([
  {
    "$match": { "Date": { "$gte": ISODate("2020-01-01") } }
  },
  {
    "$set": { "ratio": { "$divide": [ "$B", { "$toDouble": "$A" } ] } }
  },
  {
    "$match": { "ratio": { "$lte": 0.1 } }
  },
  {
    "$sort": { "ratio": 1 }
  },
  {
    "$project": { "ratio": 0 }
  }
])

Пример

person J.F.    schedule 24.11.2020
comment
Почему вам нужно использовать $project здесь? - person Gal Dreiman; 24.11.2020
comment
Я добавил новое поле ratio и предполагаю, что вы не хотите выводить это поле. - person J.F.; 24.11.2020
comment
Понял, спасибо. - person Gal Dreiman; 24.11.2020
comment
Пожалуйста! Кроме того, я обновил запрос, чтобы он не делился дважды. Существует только одно деление и только для документа, date которого совпало. - person J.F.; 24.11.2020