#mongodb #mongodb-query
#mongodb — монгодб #mongodb-запрос #mongodb
Вопрос:
У меня есть следующие 3 документа в mongodb:
документ 1:
{
"name": "device1",
"camera": {
"number": 3
}
}
документ 2:
{
"name": "device2",
"camera": {
"number": 1
}
}
документ 3:
{
"name": "device3",
"wifi": {
"number": 2
}
}
Моя цель — найти все устройства, номер модулей которых > 1, возможно, модуль camera
, wifi
или другие.
Я знаю, что могу использовать next для получения устройства:
> db.devices.find({"camera.number":{$gt:1}})
{ "_id" : ObjectId("5f436a3df716cb47d319245e"), "name" : "device1", "camera" : { "number" : 3 } }
> db.devices.find({"wifi.number":{$gt:1}})
{ "_id" : ObjectId("5f436a58f716cb47d3192460"), "name" : "device3", "wifi" : { "number" : 2 } }
Но, похоже, мне пришлось добавить что-то вроде «module.number» в запрос, вы знаете, может быть, у меня много модулей, тогда не так эффективно использовать camera.number
, wifi.number
amp; othermodule.number
чтобы найти все подходящие устройства. Если возможно, у меня может быть что-нибудь волшебное, чтобы напрямую получить устройство, которое «имеет номер любого модуля> 1», я имею в виду, что нет необходимости указывать родительское поле?
Ответ №1:
Все просто, просто измените свою схему.
https://mongoplayground.net/p/npSvVzbnsyk
{
"name": "device1",
"modules": [
{
"k": "camera",
"v": 3
}
]
},
{
"name": "device2",
"modules": [
{
"k": "wifi",
"v": 3
},
{
"k": "camera",
"v": 2
}
]
},
{
"name": "device3",
"modules": [
{
"k": "wifi",
"v": 2
}
]
}
db.collection.find({"modules.v": 3})
Ответ №2:
Я не думаю, что это возможно с помощью find()
метода, но вы можете попробовать метод aggregate(),
- $addFields добавит
device
поле, которое преобразует$$ROOT
объект в массив вk
иv
форматирует с помощью $objectToArray - $match вы можете сопоставить
device.v.number
с вашим номером - $project для скрытия
device
поля
db.devices.aggregate([
{ $addFields: { device: { $objectToArray: "$$ROOT" } } },
{ $match: { "device.v.number": { $gt: 1 } } },
{ $project: { device: 0 } }
])
Другой возможный способ с aggregate()
методом,
- сопоставление с $expr
- $ reduce будет вводить
$$ROOT
как$objectToArray
, а внутриin
проверяет условие, если число равно нулю, используя $ifNull, затем$add
число в initialValue, иначе добавьте0
.
db.collection.aggregate([
{
$match: {
$expr: {
$gt: [
{
$reduce: {
input: { $objectToArray: "$$ROOT" },
initialValue: 0,
in: { $add: ["$$value", { $ifNull: ["$$this.v.number", 0] }] }
}
},
1 // add your search number
]
}
}
}
])
Комментарии:
1. Новичок в mongodb, позвольте мне когда-нибудь разобраться, скоро вернется.
2. Хорошо, добавлены ссылочные ссылки по конвейеру.
3.
{ $addFields: { device: { $objectToArray: "$$ROOT" } } }
Возникнет ли какая-либо проблема с эффективностью? Преобразовать документ вk-v
и добавитьdevice
в качестве поля?4. Я предполагаю, что это компромисс, чтобы использовать это по сравнению с использованием предопределенного
k-v
как и в другом упомянутом ответе, я попробую его производительность с моими собственными реальными наборами данных, спасибо за информацию.5. $ addFields добавит новое поле, которое генерируется из корня всех полей текущего документа, так что, возможно, это займет немного больше памяти, я добавил другое решение с единственным совпадением, оно лучше, чем первый запрос, вы можете проверить разницу в эффективности обоих запросов, используя explain