codemonkey
codemonkey

Reputation: 7905

How to invert a MongoDB aggregation result?

I apologize if this is a silly question, but is there an easy way to invert a MongoDB result? My aggregation pipeline returns this:

[
  {
    email: "[email protected]",
    phone: "1290740373"
  },
  {
    email: "[email protected]",
    phone: "1455414441"
  },
  {
    email: "[email protected]"
  }
  ...
]

Is there a way to get something like this out:

{
"[email protected]": 1,
"1290740373": 1,
"[email protected]": 1,
"1455414441": 1,
"[email protected]": 1
}

I am fully aware that a library like lodash can do that with one line of code inside the app, but I was hoping to accomplish this on the DB level if it's not too cumbersome.

Upvotes: 0

Views: 299

Answers (1)

Wernfried Domscheit
Wernfried Domscheit

Reputation: 59456

You have two challenges, first you have to convert field values to field names. This is achieved with $objectToArray and $arrayToObject.

Second you have to translate all documents into one document. For this I use $group and $reduce

db.collection.aggregate([
  { $unset: "_id" },
  // transform field values into field names 
  { $set: { data: { $objectToArray: "$$ROOT" } } },
  {
    $set: {
      data: {
        $map: {
          input: "$data",
          in: { k: "$$this.v", v: 1 }
        }
      }
    }
  },
  { $replaceRoot: { newRoot: { $arrayToObject: "$data" } } },
  // Merge all documents into one
  {
    $group: {
      _id: null,
      data: { $push: "$$ROOT" } 
    }
  },
  {
    $replaceRoot: {
      newRoot: {
        $reduce: {
          input: "$data",
          initialValue: {},
          in: { $mergeObjects: [ "$$value", "$$this" ] }
        }
      }
    }
  }
])

See Mongo playground

Upvotes: 3

Related Questions