Search code examples
arraysmongodbmongodb-queryaggregate

How do I the merge the results of a facet into a list, with conditions, in mongodb?


I have a facet with the following result:

{
    directConfigs: [
        type: "Type A",
        result: {
            priority: 2,
            id: ObjectId('63c6a4b858612f44f37d4771')
        },
        type: "Type B",
        result: {
            priority: 3,
            id: ObjectId('63bd7878f1f085f7d8a6827f')
        }
    ],
    indirectConfigs: [
        type: "Type A",
        result: {
            priority: 1,
            id: ObjectId('627279d3ba7aef5d6418c867')
        },
        type: "Type C",
        result: {
            priority: 5,
            id: ObjectId('63be730bf1f085f7d8a682c8')
        }
    ],
}

From this result I want to get a list of objects grouped on the type field. The rules are that directConfigs have priority over indirectConfigs. So if both arrays have a Type A config, we want the one in directConfigs. I've already made sure that each of the types can only occur once in each of the arrays. The result should look like this:

result: [
    {
        type: "Type A",
        result: {
            priority: 2,
            id: ObjectId('63c6a4b858612f44f37d4771')
        }
    },
    {
        type: "Type B",
        result: {
            priority: 3,
            id: ObjectId('63bd7878f1f085f7d8a6827f')
        }
    },
    {
        type: "Type C",
        result: {
            priority: 5,
            id: ObjectId('63be730bf1f085f7d8a682c8')
        }
    }
]

How do I do that?


Solution

  • One option is to use $reduce:

    db.collection.aggregate([
      {$project: {
          _id: 0,
          result: {
            $reduce: {
              input: "$indirectConfigs",
              initialValue: "$directConfigs",
              in: {$concatArrays: [
                  "$$value",
                  {$cond: [
                      {$not: {$in: ["$$this.type", "$$value.type"]}},
                      ["$$this"],
                      []
                  ]}
              ]}
            }
          }
      }}
    ])
    

    See how it works on the playground example