skip to Main Content

I have a document like this in a collection:

{ 
  _id: '123', 
  locations: [ 
    {uuid:'1-1'}, 
    {uuid:'2-2'}, 
    {uuid:'3-3'}, 
    {uuid:'4-4'} 
  ] 
}

I would like to create a query that returns this:

[
  { location: { uuid:'3-3'} }
  { location: { uuid:'4-4'} }
]

Looks like a job for aggregate

Start off by:

{ $match: { _id:  123 } }

then maybe

{ $unwind: '$locations' }

then

{ $project: { _id: 0, location: '$locations'} }

Cool, this gives me:

[
  { location: { uuid: '1-1'} }
  { location: { uuid: '2-2'} }
  { location: { uuid: '3-3'} }
  { location: { uuid: '4-4'} }
]

Now i need a way to only return elements that come after ‘3-3’ (but also keep 3-3). Any ideas?

2

Answers


  1. Here the approach I took is to $slice the array from index 2 to end of array so to get the position of 3-3 i used $indexOfArray.
    Now since locations is sliced there is fewer to $unwind

    db.collection.aggregate([
      { $match: { _id: "123" } },
      {
        $project: {
          _id: 0,
          locations: {
            $slice: [ "$locations", 
                // If target is not found, $indexOfArray will return -1.
                // OP says in that case, return whole array which means
                // start at 0.
                {$max: [0, { $indexOfArray: [ "$locations", { uuid: "3-3" } ] } ] },
                { $size: "$locations" } ]
            }
        }
      },
      { $unwind: "$locations" },
      { $project: { _id: 0, location: "$locations" } }
    ])
    

    demo

    Login or Signup to reply.
  2. The accepted answer works but for extra protection, you might want to do $indexOfArray on the uuid target, not the object:

    {$max: [0,{ $indexOfArray: [ "$locations.uuid", "3-3"] }] },
    

    This ensures correct matching on only uuid. For example, assume the input objects are more complex and possibly polymorphic:

    { 
      _id: '123', 
      locations: [ 
        {uuid:'1-1', other:1}, 
        {uuid:'2-2', foo:2}, 
        {uuid:'3-3', baz:3, not_concerned:7}, 
        {uuid:'4-4', corn:4} 
      ] 
    }
    

    Then the original approach:

    { $indexOfArray: [ "$locations", { uuid: "3-3" } ] }
    

    will fail because of additional fields baz and not_concerned.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search