Отдельные значения из разных полей в коллекции MongoDB

Я использую node-mongodb-native для запуска запросов mongodb с использованием узла js. Существует коллекция с названием «местоположения», которая имеет следующие поля:

sublocality1, sublocality2, sublocality3, city.

Я хочу получить общие отдельные значения из этих полей.

Например: Документы:

{
  'sublocality1':'a',
  'sublocality2':'a',
  'sublocality3': 'b',
  'city': 'c'
}

{
  'sublocality1':'b',
  'sublocality2':'a',
  'sublocality3': 'b',
  'city': 'a'
}

Запрос должен вернуться

['a' , 'b', 'c']

Я пробовал следующее:

Run distinct queries for each of the fields:
collection.distinct('sublocality1',..){},
collection.distinct('sublocality2',..){},
collection.distinct('sublocality3',..){},
collection.distinct('city',..){}

Вставьте результат этих запросов в список и найдите отдельные элементы в списке.

Могу ли я оптимизировать это? Можно ли запустить один запрос?


person Ritesh Kumar Gupta    schedule 22.01.2015    source источник


Ответы (1)


Вы можете агрегировать его на сервере базы данных, как показано ниже:

  • Group Отдельный документ, чтобы получить значения каждого предполагаемого поля в массиве.
  • Project поле с именем values в качестве union всех предполагаемых значений поля, используя $ оператор setUnion.
  • Unwind значений.
  • Group все записи, чтобы получить различные значения.

Код:

Collection.aggregate([
{$group:{"_id":"$_id",
         "sublocality1":{$push:"$sublocality1"},
         "sublocality2":{$push:"$sublocality2"},
         "sublocality3":{$push:"$sublocality3"},
         "city":{$push:"$city"}}},
{$project:{"values":{$setUnion:["$sublocality1",
                                "$sublocality2",
                                "$sublocality3",
                                "$city"]}}},
{$unwind:"$values"},
{$group:{"_id":null,"distinct":{$addToSet:"$values"}}},
{$project:{"distinct":1,"_id":0}}
],function(err,resp){
   // handle response
})

Образец о/п:

{ "distinct" : [ "c", "a", "b" ] }

Если вы хотите, чтобы результаты были отсортированы, вы можете применить этап sort в конвейере перед финальным этапом project.

person BatScream    schedule 22.01.2015
comment
Спасибо BatScream. Но по какой-то причине он возвращает пустой массив: я пробовал collection.aggregate([ {$group:{"_id":"$_id", "subLocality1":{$push:"$address_components.subLocality1"}, "subLocality2":{$push:"$address_components.subLocality2"}, "subLocality3":{$push:"$address_components.subLocality3"}, "city":{$push:"$address_components.city"}}}, {$project:{"values":{$setUnion:["$address_components.subLocality1", "$address_components.subLocality2", - person Ritesh Kumar Gupta; 22.01.2015
comment
Из-за нехватки места я разделил свой код на два поля для комментариев. subLocity1, subLocality2 и т. д. являются вложенными документами. "address_components" : { "city" : "Hyderabad", "subLocality1" : "Khairatabad", "subLocality2" : "", "subLocality3" : "", }; - person Ritesh Kumar Gupta; 22.01.2015
comment
@ritesh_NITW Ваш $project этап неверен, он должен быть - {$project:{"values":{$setUnion:["$subLocality1","$subLocality2",...] и так далее.. - person BatScream; 22.01.2015
comment
Большое тебе спасибо. Работает как шарм. :) - person Ritesh Kumar Gupta; 22.01.2015
comment
Спасибо за объяснение и решение. Быстрый вопрос: можем ли мы изменить запрос, чтобы добавить условие: результат должен быть подстрокой поискового термина q. т.е. отдельные элементы должны содержать строку q в качестве подстроки. - person Ritesh Kumar Gupta; 22.01.2015
comment
@ritesh_NITW — в начале этапа конвейера и после этапа раскрутки — вам нужно добавить этап $match с запросом regex для фильтрации документов, начинающихся с q/^q/. Вы можете опубликовать отдельный вопрос об этом, если вы не добьетесь успеха, но он должен быть прямолинейным, очень жаль, но изменение существующего ответа отклонит его от ответа на исходный вопрос. - person BatScream; 22.01.2015
comment
Вы также можете использовать $addToSet вместо $push на этом первом этапе, это немного уменьшит конвейер. - person Zlatko; 23.01.2015
comment
@Zlatko - На самом деле, здесь это не имеет значения. Так как на этом этапе все поля будут иметь только одно значение. Этот шаг — просто преобразовать поле в массив из одного элемента. - person BatScream; 23.01.2015