MongoDB сортировать, если значение равно чему-то - PullRequest
0 голосов
/ 20 января 2020

Есть ли способ сортировки в Mongodb -> если поле равно некоторому значению?

, например:

что-то вроде этого

db.users.aggregate(
   [
     { $sort : { username : 'john' ? -1 : 1, posts: 1 } }
   ]
)

Если я хочу для сортировки, скажем, username field ..
Если имя пользователя равно "john", то в результатах поиска пользователь стоит первым

Ответы [ 2 ]

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

Невозможно

Если MongoDB не может получить порядок сортировки посредством сканирования индекса, то MongoDB использует алгоритм сортировки top-k . Этот алгоритм буферизует первые k результаты (или последние, в зависимости от порядка сортировки), видимые до сих пор базовым индексом или доступом к коллекции. Если в какой-то момент объем памяти этих результатов k превышает 32 мегабайта, запрос не будет выполнен.

https://docs.mongodb.com/manual/reference/method/cursor.sort/#limit -results

Мы не можем переопределить сортировку алгоритма, но мы можем сделать какое-то непростое решение.

Решение 1. (Хорошая производительность)

Добавить дополнительное поле (то есть order). Для "username" : "john" установите значение 0 и для других имен пользователей установите значение 1. Создать новый индекс {order: 1, username: 1, posts: 1}

Теперь при сортировке по индексированным полям john будет на первом месте.

Решение 2 (плохая производительность)

Мы делаем то же самое, но динамически.

db.users.aggregate([
  {
    $addFields: {
      order: {
        $cond: [
          {
            $eq: [
              "$username",
              "john"
            ]
          },
          0,
          1
        ]
      }
    }
  },
  {
    $sort: {
      order: 1,
      username: 1,
      posts: 1
    }
  }
])

MongoPlayground

0 голосов
/ 20 января 2020

Я думаю, вы ищете что-то подобное.

Входные документы:

{ "username" : "jack", "posts" : "hello world" }
{ "username" : "chris", "posts" : "java programming" }
{ "username" : "krish", "posts" : "mongo mongo" }
{ "username" : "john", "posts" : "rock-n-roll" }

Запрос:

db.users.aggregate( [
  { 
      $facet: {
          input_user: [
              { $match: { username: INPUT_NAME } }
          ],
          other: [
              { $match: { username: { $ne: INPUT_NAME } } },
              { $sort: { username: 1 } }
          ]
      } 
  },
  {
      $project: { result: { $concatArrays: [ "$input_user", "$other" ] } }
  }
] )

Вывод:

Когда INPUT_NAME = 'john', то порядок username: «john», «chris», «jack» и "Кри sh".

И, когда INPUT_NAME = 'some other', это: "Крис", "Джек", "Джон" и "Кри sh".



ПРИМЕЧАНИЕ:

Приведенное выше решение отлично работает с небольшими коллекциями , но не будет использовать индексы, определенные для username + posts поля - и это может привести к снижению производительности при работе с большими коллекциями.

Таким образом, можно использовать два запроса и объединить результаты. В таком случае индекс, определенный как этот, будет использоваться фильтром запроса, а также операциями сортировки: { username: 1, posts: 1 } }.

Например:

let result_1 = db.users.find( { username: { $ne: INPUT_NAME } } ).sort( { username: 1, posts: 1 } ).toArray()

let result = db.users.find( { username: INPUT_NAME } ).sort( { username: 1, posts: 1 } ).toArray().concat(result_1)

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

...