2016-01-26 4 views
1

Я пытаюсь вернуть поле массива на основе значений в этом, но используя 2-й $ eq в поле, присутствующем в массиве (массив массива конкретно), дает мне систематически пустой результатЭлемент массива совпадения совпадений в другом массиве

Вот структура часть моей коллекции:

... 
    _id: ObjectId("S"), 
    array: [ 
    { 
     X: "A", 
     Y: NumberInt(0), 
     Z: [NumberInt(5),NumberInt(6)] 
    }, 
    { 
     X: "B", 
     Y: NumberInt(1), 
     Z: [NumberInt(5),NumberInt(8)] 
    }, 
    { 
     X: "C", 
     Y: NumberInt(0) 
    } 
    ], 
    ... 

и часть моего кода:

db.collection.aggregate(
    [ 
     { $match: { _id: ObjectId("56a108914b179d6efafca6f3") } }, 
     { $project: { _id: 1, list: { $setDifference: [ { $map: { input: "$array", as: "el", in: { $cond: [ { $and: [ { $eq: [ "$$el.Y", 0 ] }, { $eq: [ "$$el.Z", 5 ] } ] }, "$$el.X", false ] } } }, [false] ] } } } 
    ] 
); 

но второй $ эк аргумент не работают ... когда я удаляю его, у меня хороший результат (без равенства $$ el.Z).

Я хочу вернуться:

{ "_id" : ObjectId("S"), "list" : [ "A" ] } 

Спасибо заранее,

С наилучшими пожеланиями.

ответ

1

Испытание $eq как совокупность условной с массивом работает немного по-другому, чем это делает в $match или регулярном запросе. Главное отличие состоит в том, что это не будет проверять каждый элемент массива, а скорее всего «массив».

Таким образом, вам в основном нужен логический возврат для массива «элементы», если они соответствуют условию. Это может быть либо еще одна операция $map для trandform, а затем тест с $anyElementTrue. Или использовать $setIsSubset:

db.collection.aggregate(
    [ 
     { "$match": { "_id": ObjectId("56a108914b179d6efafca6f3") } }, 
     { "$project":{ 
      "list": { 
       "$setDifference": [ 
        { "$map": { 
         "input": "$array", 
         "as": "el", 
         "in": { 
          "$cond": [ 
           { "$and": [ 
            { "$eq": [ "$$el.Y", 0 ] }, 
            { "$setIsSubSet": [ [5], "$$el.Z" ] } 
           ] }, 
           "$$el.X", 
           false 
          ] 
         } 
        }}, 
        [false] 
       ] 
      } 
     }} 
    ] 
); 

И, конечно, если вы используете MongoDB 3.2 или более поздней версии, то синтаксис здесь становится немного проще с $filter для того, чтобы сократить массив:

db.collection.aggregate(
    [ 
     { "$match": { "_id": ObjectId("56a108914b179d6efafca6f3") } }, 
     { "$project":{ 
      "list": { 
       "$map": { 
        "input": { "$filter": { 
         "input": "$array", 
         "as": "el", 
         "cond": { 
         "$and": [ 
          { "$eq": [ "$$el.Y", 0 ] }, 
          { "$setIsSubSet": [ [5], "$$el.Z" ] } 
         ] 
         } 
        }}, 
        "as": "el", 
        "in": "$$el.X" 
       }} 
      } 
     }} 
    ] 
); 

Но Основной случай заключается в том, что этот логический тест должен применяться к «массиву», а не к форме запроса, которая будет рассматривать каждый элемент массива. Поэтому необходимо использовать правильные операции для проверки.

Конечно, операции агрегации массивов также не так просты, как базовые операторы запросов для соответствия элементам. Поэтому, если массив даже не присутствует, вам нужно подставить этот элемент в инструкции для действительного. Оператор $ifNull имеет использование здесь:

db.collection.aggregate(
    [ 
     { "$match": { "_id": ObjectId("56a108914b179d6efafca6f3") } }, 
     { "$project":{ 
      "list": { 
       "$map": { 
        "input": { "$filter": { 
         "input": "$array", 
         "as": "el", 
         "cond": { 
         "$and": [ 
          { "$eq": [ "$$el.Y", 0 ] }, 
          { "$setIsSubSet": [ [5], { "$ifNull": [ "$$el.Z", [] ] } ] } 
         ] 
         } 
        }}, 
        "as": "el", 
        "in": "$$el.X" 
       }} 
      } 
     }} 
    ] 
); 

И снова в MongoDB 3.2 есть также $isArray, но это немного длинный синтаксис для этой цели, как она будет использоваться вместе с $cond. Тем не менее есть веские причины для этого, как показано ниже.

Но на самом деле для ваших целей имеет смысл также проверить, что условия в основном существуют где-то в элементе массива, прежде чем применять манипуляции и фильтрацию массива. Так что это часть условия $match вместо:

db.collection.aggregate(
    [ 
     { "$match": { 
      "_id": ObjectId("56a108914b179d6efafca6f3"), 
      "array": { "$elemMatch": { "Y": 0, "Z": 5 } } 
     }}, 
     { "$project":{ 
      "list": { 
       "$map": { 
        "input": { "$filter": { 
         "input": "$array", 
         "as": "el", 
         "cond": { 
         "$and": [ 
          { "$eq": [ "$$el.Y", 0 ] }, 
          { "$setIsSubSet": [ 
           [5], 
           { "$cond": [ 
            { "$isArray": "$$el.Z" }. 
            "$$el.Z", 
            ["$$el.Z"] 
           ]} 
          ]} 
         ] 
         } 
        }}, 
        "as": "el", 
        "in": "$$el.X" 
       }} 
      } 
     }} 
    ] 
); 

С снова чекой paranoind что $$el.Z фактически является массив или заменить его в оценке с чем-то, что на самом деле массивом для обработки с оператором, ожидающим массив.

В компоненте запроса $elemMatch по крайней мере выбирает только те документы, которые имеют те же условия, которые вы хотите применить в фильтре, даже если эта проверка сама по себе не гарантирует, что "Z" фактически является массивом.

+0

Mmh интересно ... спасибо! Но «$ setIsSubSet» показывает мне «errmsg»: «оба операнда $ setIsSubset должны быть массивами. Первый аргумент имеет тип: EOO» и возвращает NULL, если я использую [] вокруг моего «$$ el.Z» –

+1

@JohnS Не вставляйте в '[]', так как само поле уже является массивом. Другой аргумент заключен в '[]' (т. Е. '[5]'), потому что это сравнение «наборов». Проверьте свой синтаксис еще раз. Я заметил, что аргументы на самом деле были неправильными, но до тех пор, пока '$$ el.Z' всегда разрешает массив, нет проблем. Ошибка предполагает, что элемент отсутствует в некоторых документах. Используйте '$ ifNull', если это так. –

+0

Спасибо вам за помощь. Он работает хорошо, и, таким образом, вы помогли мне лучше понять работу агрегатов! –

Смежные вопросы