Запрос Mongoose для сопоставления массива документов, независимо от порядка его элементов

Используя MongoDB/Mongoose, рассмотрим мою коллекцию test, имеющую следующие 2 документа:

"_id" : ObjectId("5c4e3cef9cd12904cfc7ecc0"),
"name" : "REGISTER1",
"properties" : [
        {
            "property” : "PROP1",
            "value" : "GREEN"
        },
        {
            "property” : "PROP2",
            "value" : "RED"
        }
    ]

и

"_id" : ObjectId("5c4e3cef9cd12904cfc7ecc0"),
"name" : "REGISTER2",
"properties" : [
        {
            "property" : "PROP2",
            "value" : "RED"
        },
        {
            "property" : "PROP1",
            "value" : "GREEN"
        }
    ]

Я использую следующие команды для поиска регистров:

db.tests.find(
   { properties: [
            {
                "property" : "PROP2",
                "value" : "RED"
            },
            {
                "property" : "PROP1",
                "value" : "GREEN"
            }
        ]
   }).pretty();

Это возвращает REGISTER2, а не REGISTER1.

Таким же образом:

db.tests.find(
   { properties: [
            {
                "property" : "PROP1",
                "value" : "GREEN"
            },
            {
                "property" : "PROP2",
                "value" : "RED"
            }
        ]
   }).pretty();

Это возвращает REGISTER1, а не REGISTER2.

Мне нужно, чтобы оба запроса возвращали оба элемента «REGISTER1» и «REGISTER2», поскольку единственное изменение между ними — это порядок свойств (порядок массива).

Как я могу запросить возврат как REGISTER1, так и REGISTER2, независимо от порядка элементов запроса в массиве?

🤔 А знаете ли вы, что...
MongoDB является открытым исходным кодом и доступна под лицензией GNU AGPL...


2
125
2

Ответы:

Имя свойства в первом документе — property_id, а во втором — property.

Пожалуйста, используйте $elemMatch с $or, чтобы получить оба совпадающих документа

db.tests.find({
    properties : {$elemMatch : {$or : [
        {"property" : "PROP1", "value" : "GREEN"},
        {"property" : "PROP2", "value" : "RED"}
    ]}}
})

сбор образцов

> db.tests.find()
{ "_id" : ObjectId("5c4e3cef9cd12904cfc7ecc0"), "name" : "REGISTER1", "properties" : [ { "property" : "PROP1", "value" : "GREEN" }, { "property" : "PROP2", "value" : "RED" } ] }
{ "_id" : ObjectId("5c4e3cef9cd12904cfc7ecc1"), "name" : "REGISTER2", "properties" : [ { "property" : "PROP2", "value" : "RED" }, { "property" : "PROP1", "value" : "GREEN" } ] }

найти

> db.tests.find({properties : {$elemMatch : {$or : [{"property" : "PROP1", "value" : "GREEN"},{"property" : "PROP2", "value" : "RED"}]}}})
{ "_id" : ObjectId("5c4e3cef9cd12904cfc7ecc0"), "name" : "REGISTER1", "properties" : [ { "property" : "PROP1", "value" : "GREEN" }, { "property" : "PROP2", "value" : "RED" } ] }
{ "_id" : ObjectId("5c4e3cef9cd12904cfc7ecc1"), "name" : "REGISTER2", "properties" : [ { "property" : "PROP2", "value" : "RED" }, { "property" : "PROP1", "value" : "GREEN" } ] }
>

Решено

Для этого вы можете использовать запрос $all:

db.tests.find({
  properties: {$all: [
   {property: 'PROP1', value: 'GREEN'},
   {property: 'PROP2', value: 'RED'} 
]}})

Оба элемента $all должны существовать для соответствия документа, но порядок не имеет значения.

В случае, когда элементы properties содержат больше ключей помимо того, что вы сопоставляете, вы можете использовать $elemMatch:

db.tests.find({
  properties: {$all: [
   {$elemMatch: {property: 'PROP1', value: 'GREEN'}},
   {$elemMatch: {property: 'PROP2', value: 'RED'}} 
]}})

$elemMatch гарантирует, что каждый кортеж property/value соответствует одному и тому же элементу.