How to compare 2 collections and fetch matched field data in mongodb? - arrays

I have a two collection as given below.
Collection 1: List
{
"_id" : ObjectId("5b618589d6edcc135c1aee0a"),
"name" : "ABC",
"special" : "Golmal",
"dim" : "2122",
}
Collection 2: Data
Document 1:
{
"_id" : ObjectId("5b6023d9589ff6bfb5dd75d7"),
"date" : "2018/08/13",
"special" : "Golmal",
}
Document 2:
{
"_id" : ObjectId("5b602447589ff6bfb5dd7606"),
"date" : "2018/08/13",
"special" : "Godman",
}
Here I want compare both the collection and if "special":"Golmal" of Collection 1 is present in Collection 2 documents I want to display/fetch all the related date from Collection 1 document.
I have tried aggregate & $lookup as below
getAvailableList(): Promise<any> {
return this._mongoUtility.Db
.then(db => {
let list= db.collection('list');
let data= db.collection('data');
list.aggregate([{$lookup:
{
from: data,
localField: "special",
foreignField: "special",
as: "matches"
}
},
{
$match: { "matches": { $ne: [{}] } }
}
]);
return Promise.resolve();
})
.catch(err => {
return Promise.reject({message: 'Not found', err: err});
});
}
But I'm getting null.
I have also tied by using .find & forEach as below
let abc = [];
list.find({}).toArray()
.then(arr => {
arr.forEach(obj1 => {
data.find({special: obj1.special}).toArray()
.then(secondArr => {
console.log(secondArr);
if (secondArr.length > 0) {
abc.push(obj1);
}
});
});
});
return Promise.resolve();
But no result. I need value in JSON format. As MongoDB dont have joins. Is there any ways to crack it?

Well, I changed my way of doing that query by not using forEach and its working for me.
I come across $in in find in mongoDB website. Here's the answer
return new Promise((res, rej) => {
this._mongoUtility.Db
.then(db => {
let list= db.collection('List');
let data= db.collection('Data');
data.find({}).toArray()
.then(arr => {
let maps = arr.map(data => data.special);
list.find({special: {$in: maps}}).toArray()
.then(secondArr => {
res(secondArr);
});
});
})
.catch(err => {
return rej({message: 'Not found', err: err});
});
});

As of MongoDB 3.2, joins become possible.
https://www.mongodb.com/blog/post/joins-and-other-aggregation-enhancements-coming-in-mongodb-3-2-part-1-of-3-introduction

Related

How can I realize "find" with using "$in" by two parameters in mangoose?

Hi I have the function which get object with id array like this.
{
"participants": [
"5fa566b5b96a9407c804ccd4",
"5fa5639cb96a9407c804ccce"
]
}
And I need to find object which have exactly this fields
Objects in which i try to find it looks like this:
{
"_id" : ObjectId("5fac288e53a6a72e94f721fa"),
"participants" : [
ObjectId("5fa566b5b96a9407c804ccd5"),
ObjectId("5fa5639cb96a9407c804ccc5")
],
"messages" : [],
}
I am trying to do like this but it doesn't work.
async filterDialog(newDialog: any){
const res = await Dialog.find({
'participants': { $in: { ...newDialog.participants } }, function(err: any, dialog: any) {
if (err) {
return err
} else {
return dialog
}
},
})
return res;
}
Will be glad if someone help me.
I think you need $all operator.
Check this query:
db.collection.find({
"participants": {
"$all": yourArray
}
})
Only return the document where the field participants contains all element from the given array.
Example here where I've used numbers instead of ObjectId to read easier.
Please check if this is the behavior you expect.

MongoDB $push nested arrays

I'm working on a food blog. I would want to achieve the following structure for the food recipes in my database.
recipes : [
{mainCategoryRecipe1: {...}},
{mainCategoryRecipe2: {...}},
subcategory1: [
{recipe1: {...}}
]
]
I'm posting a form with select field indicating the correct category and subcategory (if needed). I can access these in the Node.js backend.
I can't figure out how to $push in to the database so the data follows the correct structure. I'm using MongoJS. My attempt on this resolves with this structure instead:
recipes : [
{subcategory1 : recipe1[...]},
{subcategory1 : recipe2[...]}
]
Here is my code:
db.collection.findAndModify({
query:{_id: mongojs.ObjectId(userId)},
update: { $push: {
recipes : {
[recipe.subcategory] : recipe
}
}},
new: true
}, function(err, doc, lastErrorObject){
if(err){
throw (err)
} else {
//console.log(recipe)
res.render('/success');
}
});
Thank you in advance!
Try with the code belove, If you have any errors please comment them.
db.collection.findOneAndUpdate({
{_id: new ObjectID(userId)},
{ $push: {
recipes : {
[recipe.subcategory] : recipe
}
}},
returnOriginal: false
}, function(err, doc, lastErrorObject){
if(err){
throw (err)
} else {
//console.log(recipe)
res.render('/success');
}
});

Add array values into MongoDB where element is not in array

In MongoDB, this is the simplified structure of my account document:
{
"_id" : ObjectId("5a70a60ca7fbc476caea5e59"),
"templates" : [
{
"name" : "Password Reset",
"content" : "AAAAAAAA"
},
{
"name" : "Welcome Message",
"content" : "BBBBBB"
}
]
}
There's a similar default_templates collection
let accnt = await Account.findOne({ _id: req.account._id }, { templates: 1 });
let defaults = await DefaultTemplate.find({}).lean();
My goal is to find the missing templates under account and grab them from defaults. (a) I need to upsert templates if it doesn't exist in an account and (b) I don't want to update a template if it already exists in an account.
I've tried the following:
if (!accnt.templates || accnt.templates.length < defaults.length) {
const accountTemplates = _.filter(accnt.templates, 'name');
const templateNames = _.map(accountTemplates, 'name');
Account.update({ _id: req.account._id, 'templates.name' : { $nin: templateNames } },
{ '$push': { 'templates': { '$each' : defaults } } }, { 'upsert' : true },
function(err, result) {
Logger.error('error %o', err);
Logger.debug('result %o', result);
}
);
}
This succeeds at the upsert but it will enter all default templates even if there's a matching name in templateNames. I've verified that templateNames array is correct and I've also tried using $addToSet instead of $push, so I must not understand Mongo subdoc queries.
Any ideas on what I'm doing wrong?
Edit: I've gotten this to work by simply removing elements from the defaults array before updating, but I'd still like to know how this could be accomplished with Mongoose.
You can try with bulkWrite operation in mongodb
Account.bulkWrite(
req.body.accountTemplates.map((data) =>
({
updateOne: {
filter: { _id: req.account._id, 'templates.name' : { $ne: data.name } },
update: { $push: { templates: { $each : data } } },
upsert : true
}
})
)
})

How to increase counter on repetition of value under an array mongodb

I have a mongoose schema like this:
{
"_id" : ObjectId("5a7acda13b808dbed05d6505"),
"symbol" : "#AKS",
"counter" : 4
},
{
"_id" : ObjectId("5a7acda13b808dbed05d6506"),
"symbol" : "#AKD",
"counter" : 5
}
Now if I want to update multiple column i.e "symbol" values on one query then MongoDB updateMany Query will do. This is Query:
MyCollectionName.updateMany({ 'symbol' : { $in : req.body.array}}, { $inc : { 'counter': 1 } }, function(err, data) {
if(err) {
console.log('error')
} else {
console.log('value incremented')
}
});
By this Query If I give the Array value i.e
var array = ["#AKS", "#AKD"];
Then it will Increment the counter of Both. My Question is If I will Provide the Same value on an array then I want Two increment not one. Like this:
var array = ["#AKS", "#AKS"];
//I want the Increment of 2.
var array = [#AKS", "#AKS", "#AKS", "#AKS"]
//at this stage I want the counter of Increment is 4
But currently it will do Only One. Is this possible????
Any help is really appreciated.
You can use the bulkWrite API for this update as it allows you to compose an array of bulkWrite() write operations in which you can use the updateOne operation for each element in the array. The following example shows how you can apply it in your case:
let ops = [];
const handleResult = res => console.log(res);
const handleError = err => console.error(err);
req.body.array.forEach(function(item) {
ops.push({
"updateOne": {
"filter": { "symbol": item },
"update": { "$inc": { "counter": 1 } }
}
});
if (ops.length === 1000) {
MyCollectionName.bulkWrite(ops).then(handleResult).catch(handleError);
ops = [];
}
})
if (ops.length > 0) MyCollectionName.bulkWrite(ops).then(handleResult).catch(handleError);
what if instead of using updateMany you just forEach your array:
const yourArray = req.body.array;
yourArray.forEach(function(item) {
MyCollectionName.update({ 'symbol': { $in: item }}, { $inc: { 'counter': 1 }, function (err, data) {
// additional code
});
});

Remove from array of objectId using update mongoDB

I have a model named courier, it has an array named order and orders has some ObjectIds of model order, how can I remove an element from orders array using update or something else ?
(for example removing an order with specific id)
Here is my model:
courier:
var courierSchema = new Schema({
name: { type: String },
orders:[{type:Schema.Types.ObjectId,ref:'order'}],
});
I tried this code but it fails :
courier.update({
name: 'Mahan'
}, {
$pull : {
orders: {
_id: order._id
}
}
}, (err, count, obj) => {
if(err) {
console.log(err);
return handleError(err, reply);
}
console.log(count);
});
Is there any way to do this not using find, remove and then save ?
This would be the most efficient format to achieve what you are trying to do
db.collection.update({<cond to identify document}, {$pull: {'orders': {'id': <id>}}} )

Resources