Учитывая перечень документов, таких как:
[
{
_id: 1,
field1: "test",
field2: "value2",
fields: [
"field1",
"field2"
]
},
{
_id: 2,
field1: "value1",
field2: "test",
fields: [
"field1",
"field2"
]
},
{
_id: 3,
field1: "test",
field2: "value2",
fields: [
"field2"
]
},
{
_id: 4,
field1: "value1",
field2: "value2",
fields: [
"field1"
]
},
{
_id: 5,
field1: "test",
field2: "test",
fields: []
}
]
Я хочу получить все документы, которые имеют любое из указанных полей в массиве со значением «тест». Например, в документе с _id: 1
field2
является значением массива fields
, а field2
имеет test
в качестве значения. Напротив, документ с _id: 5
имеет ключи field1
и field2
с проверочным значением, но ни одно из этих полей не присутствует в массиве полей. Итак, учитывая предыдущий список документов, возвращать следует только документы с _id: 1
и _id: 2
.
еще лучше с $in mongoplayground.net/p/-4hn4gibp-0 в первом $addField
возможный подход в виде шагов
field1
,field2
.., чтобы его можно было фильтровать/искать.Подход с $anyElementTrue
на стадии матча - демо
db.collection.aggregate([
{
$addFields: {
keyValuePairArray: {
$filter: {
input: { $objectToArray: "$$ROOT" },
cond: { $not: { $in: [ "$$this.k", ["_id", "fields"] ] } }
}
}
}
},
{
$match: {
$expr: {
$anyElementTrue: {
$map: {
input: "$keyValuePairArray",
in: {
$and: [
{ $in: [ "$$this.k", "$fields" ] },
{ $eq: [ "$$this.v", "test" ] }
]
}
}
}
}
}
},
{ $unset: "keyValuePairArray" }
])
Другой подход с $filter
на этапе матча, проверив его размер - демо
db.collection.aggregate([
{
$addFields: {
keyValuePairArray: {
$filter: {
input: { $objectToArray: "$$ROOT" },
cond: { $not: { $in: [ "$$this.k", ["_id", "fields"] ] } }
}
}
}
},
{
$match: {
$expr: {
$gt: [
{
$size: {
$filter: {
input: "$keyValuePairArray",
cond: {
$and: [
{ $in: [ "$$this.k", "$fields" ] },
{ $eq: [ "$$this.v", "test" ] }
]
}
}
}
},
0
]
}
}
},
{ $unset: "keyValuePairArray" }
])
РЕДАКТИРОВАНИЕ - вам может даже не понадобиться временное поле, удалив _id
и fields
, поскольку они все равно не повлияют на сравнение $match
- проверьте демо
db.collection.aggregate([
{
$match: {
$expr: {
$anyElementTrue: {
$map: {
input: { $objectToArray: "$$ROOT" },
in: {
$and: [
{ $in: [ "$$this.k", "$fields" ] },
{ $eq: [ "$$this.v", "test" ] }
]
}
}
}
}
}
}
])
Я принимаю ответ, потому что он решает именно то, что я спросил. Но мой вопрос был неверным и данные тоже. Я перефразировал вопрос здесь, что немного сложнее.
что-то вроде этого, может быть mongoplayground.net/p/wVOsyL2oQrH или mongoplayground.net/p/0WGF4W4cjXA