Если я правильно понял ваш вопрос, у вас есть входной объект, который может содержать некоторые полей в объекте params
основного документа, в любом порядке, например:
{
device: "windows",
gender: "m"
}
{
gender: "m",
device: "windows"
}
{
device: "windows",
age: 28
}
и вы хотите сопоставить, только если все поля во входном объекте существуют в основном документе:
{
device: "linux", // NO MATCH
gender: "m"
}
{
gender: "m", // MATCH
device: "windows"
}
{
device: "windows", // NO MATCH
age: 29
}
Правильно?
Опция 1
Всегда ли ваш объект param
содержит только эти три поля (device
, gender
и age
)?
Если это так, вы можетевручную спроецируйте каждый из них на корневой уровень, сопоставьте и снова «отмените» их:
db.my_collection.aggregate([
{
$project: {
name: 1,
params: 1,
device: "$params.device", // add these three for your match stage
gender: "$params.gender",
age: "$params.age"
}
},
{
$match: input_params
},
{
$project: {name: 1, params: 1} // back to original
}
]);
Но я предполагаю, что вы хотите сделать это для любого числа полей внутри вашего params
объекта.
Опция 2
Есть ли у вас способ манипулировать входящим входящим объектом?Если это так, вы могли бы предварить все поля "params.
":
let input_params =
{
device: "windows",
gender: "m"
};
let new_input_params =
{
"params.device": "windows",
"params.gender": "m"
};
Тогда ваш запрос будет просто:
db.my_collection.find(new_input_params);
Вариант 3
Если у вас нет способа изменить ввод , вы можете использовать оператор агрегирования $ replaceRoot (начиная с версии 3.4, кредит этот ответ ), чтобы сгладитьваш params
в корневой документ.Поскольку это заменит корневой документ на внедренный, вам нужно сначала извлечь интересующие вас поля, по крайней мере, поле _id
:
db.my_collection.aggregate([
{
$addFields: {"params.id": "$_id"} // save _id inside the params doc,
// as you will lose the original one
},
{
$replaceRoot: {newRoot: "$params"}
},
{
$match: input_params
},
...
]);
Это будет соответствовать документам и сохранит *Поле 1057 *, которое вы можете использовать, чтобы снова получить оставшуюся часть документа, например через $lookup
:
...
{
$lookup: {
from: "my_collection",
localField: "id",
foreignField: "_id",
as: "doc"
}
},
...
Это позволит получить ваши документы в следующем формате:
{
"device" : "windows",
"gender" : "m",
"age" : 28,
"id" : ObjectId("XXX"),
"doc" : [
{
"_id" : ObjectId("XXX"),
"name" : "Test",
"params" : {
"device" : "windows",
"gender" : "m",
"age" : 28
}
}
]
}
Чтобы пройти полный круг и вернуть исходный формат документа, вы можете:
...
{
$unwind: "$doc" // get rid of the [] around the "doc" object
// ($lookup always results in array)
},
{
$replaceRoot: {newRoot: "$doc"} // get your "doc" back to the root
}
...
Пока я пишу это, я не могу поверить, что нет более чистого способа сделать это, используя только MongoDB, ноЯ не могу думать ни о чем.
Надеюсь, это поможет!