I have a collection "users" in MongoDB that have some documents such as:
{
"email": "[email protected]",
"privileges" : [
{
"domain" : "test.com:7777",
"_id" : ObjectId("59636fbf0b61c61f659d0365"),
"role" : "admin"
},
{
"domain" : "test2.com:7777",
"_id" : ObjectId("59636fbf0b61c61f659d0365"),
"role" : "admin"
}
],
},
{
"email": "[email protected]",
"privileges" : [
{
"domain" : "testxyz.com:7777",
"_id" : ObjectId("59636fbf0b61c61f659d0365"),
"role" : "admin"
}
]
},
{
"email": "[email protected]",
"privileges" : [
{
"domain" : "testabc.com",
"_id" : ObjectId("59636fbf0b61c61f659d0365"),
"role" : "admin"
}
]
}
Please notice the "case sensitive" in each email.
Now what I need to do is that I need to combine these emails into only one with lowercase and merge all privileges.
So the result should be:
{
"email": "[email protected]",
"privileges" : [
{
"domain" : "test.com:7777",
"_id" : ObjectId("59636fbf0b61c61f659d0365"),
"role" : "admin"
},
{
"domain" : "test2.com:7777",
"_id" : ObjectId("59636fbf0b61c61f659d0365"),
"role" : "admin"
},
{
"domain" : "testxyz.com:7777",
"_id" : ObjectId("59636fbf0b61c61f659d0365"),
"role" : "admin"
},
{
"domain" : "testabc.com",
"_id" : ObjectId("59636fbf0b61c61f659d0365"),
"role" : "admin"
}
],
}
Here is what I did:
const _ = require('lodash');
const async = require('async');
module.exports = (req, res, next) => {
Users.find({}).then((users) => {
async.mapLimit(users, 1, async (user) => {
let userEmail = user.email;
console.log("Loading user " + userEmail);
// Find all users that have the similar emails (case insensitive) but not the current email
let regexPattern = new RegExp(`^${userEmail}$`, "i");
let duplicateUsers = await Users.find({
$and: [
{
email: { $ne: userEmail }
},
{ email: regexPattern }
]
});
_.each(duplicateUsers, async (duplicateUser) => {
// Merge privileges
user.privileges = _.union(user.privileges, duplicateUser.privileges);
// Remove duplicate user
try {
await duplicateUser.remove();
console.log(duplicateUser.email + " is removed");
} catch (err) {
return err;
}
});
// Convert email to lowercase
user.email = user.email.toLowerCase();
user.save().then(() => {
return user;
}, (err) => {
return err;
});
}, (err) => {
if (err) throw err;
// results is now an array of the users
res.success('Done');
res.end();
});
}, next);
};
The problem is, in the end, all 3 emails are removed.
I believe that this issue happened because in the loop mapLimit, all users are processed at the same time (javascript asynchronous), because as I logged this
console.log("Loading user " + userEmail);
How should I fix this problem? Thank you.
