Chris Coddington
Chris Coddington

Reputation: 13

MongoDB : Retrieve Associated Value from Object in an Array of Arrays

In mongo I have a documents that follow the below pattern :

{
 name: "test",
 codes: [
  [
    {
      code: "abc",
      value: 123 
    },
    {
      code: "def",
      value: 456 
    },
  ],
  [
    {
      code: "ghi",
      value: 789 
    },
    {
      code: "jkl",
      value: 012 
    },
  ]
 ]
}

I'm using an aggregate query (because of joins) and in a $project block I need to return the "name" and the value of the object that has a code of "def" if it exists and an empty string if it doesn't.

I can't simply $unwind codes and $match because the "def" code is not guaranteed to be there.

$filter seems like the right approach as $elemMatch doesn't work, but its not obvious to me how to do this on nested array of arrays.

Upvotes: 1

Views: 55

Answers (1)

whoami - fakeFaceTrueSoul
whoami - fakeFaceTrueSoul

Reputation: 17915

You can try below query, instead of unwinds & filter this can give you required result with less docs to operate on :

db.collection.aggregate([
    /** merge all arrays inside codes array into code array */
    {
        $addFields: {
            codes: {
                $reduce: {
                    input: '$codes',
                    initialValue: [],
                    in: { $concatArrays: ["$$value", "$$this"] }
                }
            }
        }
    },
    /** project only needed fields & value will be either def value or '', 
     * if 'def' exists in any doc then we're check index of it to get value of that particular object using arrayElemAt */
    {
        $project: {
            _id:0, name: 1, value:
            {
                $cond: [{ $in: ["def", '$codes.code'] }, { $arrayElemAt: ['$codes.value', { $indexOfArray: ["$codes.code", 'def'] }] }, '']
            }
        }
    }])

Test : MongoDB-Playground

Upvotes: 1

Related Questions