У меня есть коллекция MongoDB с документами в следующем формате:
{
"_id" : ObjectId("4e8ae86d08101908e1000001"),
"name" : ["Name"],
"zipcode" : ["2223"]
}
{
"_id" : ObjectId("4e8ae86d08101908e1000002"),
"name" : ["Another ", "Name"],
"zipcode" : ["2224"]
}
В настоящее время я могу получить документы, соответствующие определенному размеру массива:
db.accommodations.find({ name : { $size : 2 }})
Это правильно возвращает документы с 2 элементами в массиве name
. Однако я не могу сделать команду $gt
для возврата всех документов, где поле name
имеет размер массива больше 2:
db.accommodations.find({ name : { $size: { $gt : 1 } }})
Как я могу выбрать все документы с массивом name
размером более одного (желательно без изменения текущей структуры данных)?
Update:
Для версий mongodb 2.2 + более эффективный способ сделать это, описанный @JohnnyHK в другом .
1.Использование $где
db.accommodations.find( { $where: "this.name.length > 1" } );
Но...
Javascript выполняется медленнее, чем исходные операторы, перечисленные в эта страница, но очень гибкая. См. Страницу обработки на стороне сервера для получения дополнительной информации.
2.Создайте дополнительное поле NamesArrayLength
, обновите его длиной массива имен и затем используйте в запросах:
db.accommodations.find({"NamesArrayLength": {$gt: 1} });
Это будет лучшее решение и будет работать намного быстрее (вы можете создать на нем индекс).
$where
, это очень гибкий.
Там более эффективный способ сделать это в MongoDB 2. 2+ теперь, когда вы можете использовать числовые индексы массива в ключах объектов запроса.
// Find all docs that have at least a second name array element.
db.accommodations.find({'name.1': {$exists: true}})
Вы можете поддержать этот запрос индексом, который использует выражение частичного фильтра (требуется 3. 2+):
db.accommodations.createIndex(
{'name.1': 1},
{partialFilterExpression: {'name.1': {$exists: true}}}
);
Я считаю, что это самый быстрый запрос, который отвечает на ваш вопрос, потому что он не использует интерпретированное предложение $where
:
{$nor: [
{name: {$exists: false}},
{name: {$size: 0}},
{name: {$size: 1}}
]}
Это означает "все документы, кроме тех, у которых нет имени (либо несуществующего, либо пустого массива) или только с одним именем".
Тест:
> db.test.save({})
> db.test.save({name: []})
> db.test.save({name: ['George']})
> db.test.save({name: ['George', 'Raymond']})
> db.test.save({name: ['George', 'Raymond', 'Richard']})
> db.test.save({name: ['George', 'Raymond', 'Richard', 'Martin']})
> db.test.find({$nor: [{name: {$exists: false}}, {name: {$size: 0}}, {name: {$size: 1}}]})
{ "_id" : ObjectId("511907e3fb13145a3d2e225b"), "name" : [ "George", "Raymond" ] }
{ "_id" : ObjectId("511907e3fb13145a3d2e225c"), "name" : [ "George", "Raymond", "Richard" ] }
{ "_id" : ObjectId("511907e3fb13145a3d2e225d"), "name" : [ "George", "Raymond", "Richard", "Martin" ] }
>
{'name.1': {$exists: true}}
Вы также можете использовать агрегат:
db.accommodations.aggregate(
[
{$project: {_id:1, name:1, zipcode:1,
size_of_name: {$size: "$name"}
}
},
{$match: {"size_of_name": {$gt: 1}}}
])
//вы добавляете "size_of_name" для переноса документа и используете его для фильтрации размера имени
Ничто из этого не помогло мне. Я сделал это:
db.collection.find( {arrayName : {$exists:true}, $where:'this.arrayName.length>1'} )
Попробуйте сделать что-то вроде этого:
db.getCollection('collectionName').find({'ArrayName.1': {$exists: true}})
1 - это номер, если вы хотите получить запись больше 50, то ArrayName.50 Спасибо.
Вы можете просто найти, существует ли второй элемент.
db.accommodations.find({'name.1': {$exists: true}});
db.accommodations.find({"name":{"$exists":true, "$ne":[], "$not":{"$size":1}}})
Вы можете использовать $ expr (оператор версии 3.6 mongo) для использования функций агрегации в регулярном запросе.
Сравните query operators
сравнения aggregation comparison operators
.
db.accommodations.find({$expr:{$gt:[{$size:"$name"}, 1]}})
$name
массив, являющийся вложенным документом, например, в записи "person", passport.stamps
? Я пробовал различные комбинации кавычек, но получаю "The argument to $size must be an array, but was of type: string/missing"
.
db.col.find({$expr:{$gt:[{$size:{$ifNull:["$passport.stamps", []]}}, 1]}})
Я нашел это решение, чтобы найти элементы с полем массива больше определенной длины
db.allusers.aggregate([
{$match:{username:{$exists:true}}},
{$project: { count: { $size:"$locations.lat" }}},
{$match:{count:{$gt:20}}}
])
В первом агрегате $match используется аргумент true для всех документов. Если пусто, я бы получил
"errmsg" : "exception: The argument to $size must be an Array, but was of type: EOO"
MongoDB 3.6 включает $ expr https://docs.mongodb.com/manual/reference/operator/query/expr/
Вы можете использовать $ expr для оценки выражения внутри $ match или поиска.
{$match: { $expr: {$gt: [{$size: "$yourArrayField"}, 0]} } }
или найти
collection.find({$ expr: {$ gte: [{$ size: "$ yourArrayField"}, 0]}});
Несмотря на то, что выше сказанное все работает, то, что вы изначально пытались сделать, было правильным способом, однако вы просто имеете синтаксис назад (переключатель "$ size" и "$ gt" ).
Правильно:
db.collection.find({items: {$gt: {$size: 1}}})
Неправильно:
db.collection.find({items: {$size: {$gt: 1}}})