MongoDB — различные условия запроса в зависимости от количества возвращаемых результатов

#mongodb #mongodb-query #database #nosql

#mongodb #mongodb-запрос #База данных #nosql

Вопрос:

У меня есть такой документ —

 {
type: "One",
details: "This is one",
at: "some place, where one is relevant"
}
 

Другие документы с аналогичной схемой могут иметь один и тот же «тип» с разными «деталями», «at» и т. Д.
Может быть несколько типов.

Теперь я хочу написать запрос, который вернет мне определенное количество (верхний предел, скажем, 5) документов, соответствующих определенному типу (что я могу сделать с помощью limit и $in ), который может не указывать критерий типа, если результаты содержат менее 5 документов.

Например, если я разрешаю только «Один» и «Два» в качестве «типа» и использую ограничение в 5, то, если количество результатов меньше 5 (скажем, 2), он должен вернуть мне те документы, в которых в качестве типов указаны «Один» и «Два»(т.Е. 2 документа) и еще 3 документа без учета их «типа».

Я надеюсь, что это имеет смысл!

Ответ №1:

Если вам не нравится использовать script, я вижу вариант, который используется aggregate с введением дополнительного поля weight , например, для перемещения вверх по соответствующим документам, а затем сортировки weight и ограничения общих результатов:

 db.test.aggregate({ 
  $project: {
    type: 1, 
    details: 1, 
    at: 1, 
    weight: { 
      $cond: [ 
        { "$or": [  
          {$eq: ["$type", "One"] }, 
          {$eq: ["$type", "Two"] } 
        ] }, 
      0, 1] } 
    } },  
    {$sort: {weight: 1}},
    { $limit : 5 }
);
 

Примечания к этому примеру. Я заменяю $in несколькими равными в $или для простоты. Если вам не нравится иметь weight конечный результат, вы можете удалить его, применив другую проекцию в конвейере агрегации.

Тестовая база данных:

 > db.test.find({})
{ "_id" : ObjectId("58067329a7518db4d3d2e973"), "type" : "One", "details" : "This is one", "at" : "some place, where one is relevant" }
{ "_id" : ObjectId("5806733da7518db4d3d2e974"), "type" : "Two", "details" : "This is two", "at" : "some place, where one is relevant" }
{ "_id" : ObjectId("5806734ba7518db4d3d2e975"), "type" : "Three", "details" : "This is three", "at" : "some place, where one is relevant" }
{ "_id" : ObjectId("58067374a7518db4d3d2e976"), "type" : "Four", "details" : "This is four", "at" : "some place, where one is relevant" }
{ "_id" : ObjectId("58067381a7518db4d3d2e977"), "type" : "Five", "details" : "This is five", "at" : "some place, where one is relevant" }
{ "_id" : ObjectId("5806738fa7518db4d3d2e978"), "type" : "Six", "details" : "This is six", "at" : "some place, where one is relevant" }
{ "_id" : ObjectId("580673cfa7518db4d3d2e979"), "type" : "Seven", "details" : "This is seven", "at" : "some place, where one is relevant" }    
 

Результат:

 > db.test.aggregate({ $project: { type: 1, details: 1, at: 1, weight: { $cond: [ { "$or": [  {$eq: ["$type", "One"] }, {$eq: ["$type", "Two"] } ] }, 0, 1] } } },  {$sort: {weight: 1}}, { $limit : 5 }, {$project: {type: 1, details: 1, at: 1} });
{ "_id" : ObjectId("58067329a7518db4d3d2e973"), "type" : "One", "details" : "This is one", "at" : "some place, where one is relevant" }
{ "_id" : ObjectId("5806733da7518db4d3d2e974"), "type" : "Two", "details" : "This is two", "at" : "some place, where one is relevant" }
{ "_id" : ObjectId("58067374a7518db4d3d2e976"), "type" : "Four", "details" : "This is four", "at" : "some place, where one is relevant" }
{ "_id" : ObjectId("58067381a7518db4d3d2e977"), "type" : "Five", "details" : "This is five", "at" : "some place, where one is relevant" }
{ "_id" : ObjectId("5806734ba7518db4d3d2e975"), "type" : "Three", "details" : "This is three", "at" : "some place, where one is relevant" }    
 

Комментарии:

1. Отлично @mike-shauneu ! Работает отлично! Я не могу не заметить, что в примере у нас есть только два возможных веса — я предполагаю, что один из них соответствует условию (so, 0) и не соответствует (so, 1), а затем сортируется по весу. Но можем ли мы иметь больше весов? Я думаю, что это должно быть добавлено к массиву $ cond — как условие, так и дополнительное значение веса. Так ли это?

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