Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to swap key value pair using aggregation pipeline

I have a collection that looks like so:

{ 
    "_id" : ObjectId("65977bef1ccf990fe33ffc0d"), 
    "email" : "yww24@gmail.com", 
}
{ 
    "_id" : ObjectId("65977bef1ccf990fe33ffc0f"), 
    "email" : "iqiyz@gmail.com", 
    "phone" : "8887774455"
}
{ 
    "_id" : ObjectId("65977bef1ccf990fe33ffc10"), 
    "email" : "46d9s@gmail.com"
}
{ 
    "_id" : ObjectId("65977bef1ccf990fe33ffc0e"), 
    "phone" : "6669997744"
}

I am trying to aggregate it so the result looks like this:

{
  'yww24@gmail.com': 1, // 1 can be any value (e.g. true, "yes", etc)
  'iqiyz@gmail.com': 1,
  '46d9s@gmail.com': 1,
  '8887774455': 1,
  '6669997744': 1
}

I can do that using the lodash library once the data set has been fetched from the db. I was just hoping to do this using mongodb (my assumption being that it will be less resource intensive, but I could be wrong).

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

So here is how I do it now:

Coll.aggregate([
    {
        $match: {}
    },
    {
        $project: {
            _id: false,
            email: true,
            phone: true
        }
    }
])
    .then(logs => {
        console.log(logs);
        const result = {emails: _.invertBy(logs, 'email'), phones: _.invertBy(logs, 'phone')}
        delete result.emails.undefined;
        delete result.phones.undefined;
        console.log({...result.emails, ...result.phones});

    })

Yes, the result is pretty much what I want, but, again, is there a way to do it on the db side:

{
  'yww24@gmail.com': [ '0' ],
  'iqiyz@gmail.com': [ '1' ],
  '46d9s@gmail.com': [ '2' ],
  '8887774455': [ '1' ],
  '6669997744': [ '3' ]
}

>Solution :

From my perspective, it is better not to customize the data for the projection on the database side when you can achieve it on the front-end/back-end side. Fetching data from the database should be a simple query or computation query. Imagine that when you have an extensive number of records in the database, this results in poor query performance and makes the database overloaded.

But if you are keen to do so, your query should be as follows:

  1. $group – Group all documents into one.

  2. $set – Set the data field.

    2.1. $arrayToObject – Convert an array of objects into a key-value pair.

    2.1.1. $map – Iterate each element in the array and transform into a new array.

    2.1.1.1. $setUnion – Combine arrays into an array. Alternative: $concatArrays.

  3. $replaceWith – Replace the input document with the data object.

db.collection.aggregate([
  {
    $group: {
      _id: null,
      phones: {
        $addToSet: "$email"
      },
      emails: {
        $addToSet: "$phone"
      }
    }
  },
  {
    $set: {
      data: {
        $arrayToObject: {
          $map: {
            input: {
              $setUnion: [
                "$emails",
                "$phones"
              ]
            },
            in: {
              k: "$$this",
              v: 1
            }
          }
        }
      }
    }
  },
  {
    $replaceWith: "$data"
  }
])

Demo @ Mongo Playground

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading