Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Aggregate documents where objects in array matches multiple conditions

I have a collection with documents similar to such:

{
    "_id": ObjectId("xxxxx"),
    "item": [
        { "property": ["attr1", "+1"] },
        { "property": ["attr2", "-1"] }
    ]
}

{
    "_id": ObjectId("xxxxy"),
    "item": [
        { "property": ["attr1", "-1"] },
        { "property": ["attr2", "0"] }
    ]
}

{
    "_id": ObjectId("xxxxz"),
    "item": [
        { "property": ["attr1", "0"] },
        { "property": ["attr2", "+1"] }
    ]
}

Preferably using an aggregation pipeline, is there any way to match the document if and only if any one of the properties match more than one condition?

For example, I want a query where one object in the array matches both of these conditions:

("item.property": "attr1") AND ("item.property": /^\+/)

That is, a single property where it contains "attr1" and an element that starts with "+".

However, using my current query that looks like this:

collection.aggregate(
    { $match:
        { $and: 
            [
                { "item.property": "attr1" },
                { "item.property": /^\+/ }
            ]
        }
    }

This would match both the first and last document because both contain a property with "attr1" and an element that stats with "+". However, I do not want this query to match the last document, since the element that starts with "+" does not belong to the same object in the array.

Is there any way to achieve this behavior using the aggregation framework?

like image 820
user2239520 Avatar asked Dec 15 '17 04:12

user2239520


1 Answers

You can use the below query with $elemMatch to match the array's both values.

Something like

db.collection_name.aggregate({
  "$match": {
    "item": {
      "$elemMatch": {
        "property.0": "attr1",
        "property.1": /^\+/
      }
    }
  }
});

Also, you can use $all operator if you don't want to reference array index.

db.collection_name.aggregate({
  "$match": {
    "item": {
      "$elemMatch": {
        "property": {
          "$all": [
            "attr1",
            /^\+/
          ]
        }
      }
    }
  }
});
like image 166
s7vr Avatar answered Sep 23 '22 19:09

s7vr