1

What I have is a collection of documents in MongoDB that have the structure something like this

[
  {
    "userid": "user1",
    "addresses": [
      {
        "type": "abc",
        "street": "xyz"
      },
      {
        "type": "def",
        "street": "www"
      },
      {
        "type": "hhh",
        "street": "mmm"
      },
      
    ]
  },
  {
    "userid": "user2",
    "addresses": [
      {
        "type": "abc",
        "street": "ccc"
      },
      {
        "type": "def",
        "street": "zzz"
      },
      {
        "type": "hhh",
        "street": "yyy"
      },
      
    ]
  }
]

If I can give the "type" and "userid", how can I get the result as

[
  {
    "userid": "user2",
    "type": "abc",
    "street": "ccc",   
  }
]

It would also be great even if I can get the "street" only as the result. The only constraint is I need to get it in the root element itself and not inside an array

1
  • The addresses array has three elements. Which street you like to get? always the first one? Commented Feb 1, 2022 at 16:11

2 Answers 2

3

Something like this:

db.collection.aggregate([
{
 $match: {
   userid: "user1" , "address.type":"abc"
}
},
{
$project: {
  userid: 1,
  address: {
    $filter: {
      input: "$addresses",
      as: "a",
      cond: {
        $eq: [
          "$$a.type",
          "abc"
        ]
      }
    }
  }
}
},
{
  $unwind: "$address"
},
{
$project: {
  userid: 1,
  street: "$address.street",
  _id: 0
  }
}
])

explained:

  1. Filter only documents with the userid & addresess.type you need
  2. Project/Filter only the addresses elements with the needed type
  3. unwind the address array
  4. project only the needed elements as requested

For best results create index on the { userid:1 } field or compound index on { userid:1 , address.type:1 } fields

playground

Sign up to request clarification or add additional context in comments.

Comments

0

You should be able to use unwind, match and project as shown below:

db.collection.aggregate([
{
  "$unwind": "$addresses"
},
{
  "$match": {
    "addresses.type": "abc",
    "userid": "user1"
  }
},
{
  "$project": {
    "_id": 0,
    "street": "$addresses.street"
  }
}
])

You can also duplicate the match step as the first step to reduce the number of documents to unwind.

Here is the playground link.

There is a similar question/answer here.

1 Comment

please, note using $unwind operation as first stage in aggregation pipeline is generally not recommended for big size databases in case there is option to use $match or $project stages as it is not scalable solution and it will affect query execution time proportional to the database growth ...

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.