2

I am trying to create a projection where I can take just part of a Array element.

Take this document as a model:

{
    "city_info": {
        "name": "First City"
        "initials": "FC"
    },
    "postal_codes": {
        "ranges": [
            {
                "name": "Range 1",
                "details": "More details",
                "another_object": {
                   (...)
                },
                "codes": [
                    {"code": 1},
                    {"code": 2},
                    {"code": 3}
                ]
            },
            {
                "name": "Range 2",
                "details": "More details 2",
                "another_object": {
                   (...)
                }
                "codes": [
                    {"code": 4},
                    {"code": 5}
                ]
            }
        ]
    }
}

My query would look like {"postal_codes.ranges.codes.code": 3}

Ranges and codes can have hundreads of elements. "another_object" is just a placeholder used for example.

The expected return would be like:

{
    "city_info": {
        "name": "First City"
        "initials": "FC"
    },
    "range": {
        "name": "Range 1",
        "details": "More details",
        "another_object": {
            (...)
        }
    }         
}

In short, I need to get the array element that matches the query too, but do not return it entirely.

It seems that find is not powerfull enough, I would need some kind of aggregation. I have tried to use a match to return only the documents that match the query, but I do not know how to project only part of the array.

2
  • Your JSON structure is not valid. "codes": [ "code": 4, "code": 5 ] should be "codes": [{ "code": 4, "code": 5 }]. Isn't? Commented Jul 9, 2020 at 16:23
  • Well noticed, I fixed it to an array of objects with code. Commented Jul 9, 2020 at 17:39

2 Answers 2

3

You have invalid codes structure. This cannot be inserted in Mongodb

"codes": [
  "code": 1,
  "code": 2,
  "code": 3
]

If you need to keep three codes, valid JSON would be

"codes": [
  1,2,3
]

So sample data:

{
    "_id" : ObjectId("5f074307e96d8884b6bdbdd5"),
    "city_info" : {
        "name" : "First City",
        "initials" : "FC"
    },
    "postal_codes" : {
        "ranges" : [ 
            {
                "name" : "Range 1",
                "details" : "More details",
                "another_object" : {},
                "codes" : [ 
                    1, 
                    2, 
                    3
                ]
            }, 
            {
                "name" : "Range 2",
                "details" : "More details 2",
                "another_object" : {},
                "codes" : [ 
                    4, 
                    5
                ]
            }
        ]
    }
}

Query to get:

db.getCollection('test2').aggregate([
  {
    $unwind: "$postal_codes.ranges"
  },
  {
    $unwind: "$postal_codes.ranges.codes"
  },
  {
    $match: {
      "postal_codes.ranges.codes": 3
    }
  }

])

Output:

/* 1 */
{
    "_id" : ObjectId("5f074307e96d8884b6bdbdd5"),
    "city_info" : {
        "name" : "First City",
        "initials" : "FC"
    },
    "postal_codes" : {
        "ranges" : {
            "name" : "Range 1",
            "details" : "More details",
            "another_object" : {},
            "codes" : 3
        }
    }
}

To avoid codes in the output, you need to use $project as last pipeline

{
 $project:{"postal_codes.ranges.codes":0}
}
Sign up to request clarification or add additional context in comments.

1 Comment

in this how do we get the first matching element only? i.e wherever it matches 3 just return it and project it along with other required properties from the document.
2

You need to use $unwind to convert Array into Objects and then use $match

Try this query,

db.collection.aggregate([
  { "$unwind": "$postal_codes" },
  { "$unwind": "$postal_codes.ranges.codes"},
  { "$match" : { "postal_codes.ranges.codes" : { "$eq": 3 } }},
  { "$project" : { "city_info": 1, "ranges": "$postal_codes.ranges" }}
])

Hope, this may help you.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.