1

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.

2
  • This question is still unclear, So you just need name, value, value can either be ' ' or 456 ?? Can you edit this question with an expected output !! Commented Feb 27, 2020 at 1:07
  • 1
    I don't seem to be able to edit the question but the return value would be: { name: "test", value: 456 } Commented Feb 27, 2020 at 15:01

1 Answer 1

1

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

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

1 Comment

You are a freaking genius. Thank you! I couldn't upvote but this is definitely the answer.

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.