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).
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:
-
$group– Group all documents into one. -
$set– Set thedatafield.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. -
$replaceWith– Replace the input document with thedataobject.
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"
}
])