mongodb update two array values based on array unique id's - node.js

this is my mongodb document. i want to update comment and likerName field at one query based on comments.user and likerName.likerId. i have done so far this
Tutorial.updateMany(
{
"comments.user":userid
},
{
$set:{'comments.$[].profilepic':image}
}
).then(data=>{
// res.send(data);
}).catch(err=>{
console.log(err);
})
it updates very well comment field. but i also want to update likerName field same like this.

do u mean?
{
$or:[{"comments.user":userid},{"likerName.likerId":userid}]
},

Related

How to improve the performance of query in mongodb?

I have a collection in MongoDB with more than 5 million documents. Whenever I create a document inside the same collection I have to check if there exists any document with same title and if it exists then I don't have to add this to the database.
Example: here is my MongoDB document:
{
"_id":ObjectId("3a434sa3242424sdsdw"),
"title":"Lost in space",
"desc":"this is description"
}
Now whenever a new document is being created in the collection, I want to check if the same title already exists in any of the documents and if it does not exists, then only I want to add it to the database.
Currently, I am using findOne query and checking for the title, if it not available only then it is added to the database. I am facing the performance issue in this. It is taking too much time to do this process. Please suggest a better approach.
async function addToDB(data){
let result= await db.collection('testCol').findOne({title:data.title});
if(result==null){
await db.collection('testCol').insertOne(data);
}else{
console.log("already exists in db");
}
}
You can reduce the network round trip time which is currently 2X. Because you execute two queries. One for find then one for update. You can combine them into one query as below.
db.collection.update(
<query>,
{ $setOnInsert: { <field1>: <value1>, ... } },
{ upsert: true }
)
It will not update if already exists.
db.test.update(
{"key1":"1"},
{ $setOnInsert: { "key":"2"} },
{ upsert: true }
)
It looks for document with key1 is 1. If it finds, it skips. If not, it inserts using the data provided in the object of setOnInsert.

NodeJS MongoDb updateMany() with a condition?

I want to update a MongoDb collection with an Array of JSON objects.
However, I want the update to ignore any objects that already exist in the DB.
Sounds easy, but the key that allows me to know if the object exists is not the '_id', but a different 'id' (or other key).
Is that possible ?
Currently I am using it like this:
dbHandle.collection('contents').updateMany(contents);
where 'contents' is the Array of JSON objects.
Thanks in advance
The following operation updates all documents where violations are greater than 4 and $set a flag for review:
try {
db.restaurant.updateMany(
{ violations: { $gt: 4 } }, //Your Condition
{ $set: { "Review" : true } } //YOUR JSON contents
);
} catch (e) {
print(e);
}
Change the condition accordingly.

MongoDb: Insert or update multiple documents with a unique index

I have a MongoDB collection with a unique index.
I am trying to insert or update an array of documents into that collection.
If there is NO existing document in the collection matching the unique index of the document, that new document should be inserted into the collection.
However, if there IS already a document in the collection with that unique index, it should be updated with the fields of the new document. Any fields that are NOT present in the new document should be left untouched.
This is what I have currently which is working for inserting (but NOT for updating).
const mongojs = require('mongojs');
const db = mongojs('mongodb://username:password#address.mlab.com:37230/database');
// items is an array of documents
db.items.insert(items, (err, task) => {
if (err) {
console.log(err);
}
})
I understand this is wrong and it currently gives this error:
E11000 duplicate key error index: database.items.$upc_1 dup key:
What is the proper query for this?
You can try using mongodb bulkWrite api:
var ops = []
items.forEach(item => {
ops.push(
{
updateOne: {
filter: { _id: unique_id },
update: {
$set: { fields_to_set_if_exists },
$setOnInsert: { fileds_to_insert_if_does_not_exist }
},
upsert: true
}
}
)
})
db.collections('collection_name').bulkWrite(ops, { ordered: false });
I don't believe that you can update an entire array of documents at the same time. Therefore, you would have to update each item in the array individually.
items.forEach((item) => {
db.items.update({_id: item._id}, item, {upsert: true}, (err, task) => {
if (err) {
console.log(err);
}
});
}
The {upsert: true} option will update if a record exists and insert if not.
What are you looking for is an upsert, not an insert. It can be done by the following code:
db.collection.update(
<query>,
<updates>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>,
collation: <document>
}
)
Query will search for a document using the parameters of the query, if it finds, it will update the fields mentioned in . If it doesn't find, it will insert a new document with the fields and values of .
The last object (with multiple fields), contains a field to say if an upsert is desired and one called "multi" to say if an update on multiple documents is desired.
For example:
db.items.update({name:"item1"},{$set:{price:20}},{upsert:true})
This will search for a document with the name "item1" and set its price to 20. If it doesn't find, it will create a new one with price 20.
One thing to be noticed though is:
If you don't use the tag $set on the fields, it will substitute the whole document.
Supposing you have a document like this:
{_id:"1234",name:"item1",price:10}
If you run the following two queries:
db.items.update({name:"item1"},{$set:{price:20}},...)
and
db.items.update({name:"item1"},{price:20},...)
it will yeld different results:
First one:
{_id:"1234",name:"item1",price:20}
Second one:
{_id:"1234",price:20}
If you don't call $set, it will change the whole document.
More information on the manual:
https://docs.mongodb.com/manual/reference/method/db.collection.update/
Hope my answer was helpful

Inserting the records in the table if not exists after sequelize.sync({force:true}) is called

I need to add some records to the table if there is no record exists. For now, I have written the logic to add the records in the callback function of the sequelize.sync({force:true}). I have checked whether the table contains atleast one record, and if not, I have inserted the set of records. Is there any other elegent way to obtain this functionality?
I'm reaaaaaly late to this question, but you can use findOrCreate
Like.findOrCreate({
where: {//object containing fields to found
InstagramPostId: inputLike.InstagramPostId,
InstagramUserId: inputLike.InstagramUserId
},
defaults: {//object containing fields and values to apply
postInstagramPostId: inputLike.postInstagramPostId,
userInstagramUserId: inputLike.userInstagramUserId
}
}).error(function(err){//error handling
console.log(err);
}).then(function(){//run your calllback here
console.log("callback!!");
});
Updated 02/07/2021: Use this code: Tested! Run ok.
Like.findOrCreate({
where: {//object containing fields to found
InstagramPostId: inputLike.InstagramPostId,
InstagramUserId: inputLike.InstagramUserId
},
defaults: {//object containing fields and values to apply
postInstagramPostId: inputLike.postInstagramPostId,
userInstagramUserId: inputLike.userInstagramUserId
}
}).then(function(){//run your calllback here
console.log("callback!!");
}).catch(err => {
res.status(500).send("Error -> " + err);
});

How to populate Comment count to an Item list?

I have two models in my app: Item and Comment. An Item can have many Comments, and a Comment instance contains a reference to an Item instance with key 'comment', to keep track of the relationship.
Now I have to send a JSON list of all Items with their Comment count when user requests on a particular URL.
function(req, res){
return Item.find()
.exec(function(err, items) {
return res.send(items);
});
};
I am not sure how can I "populate" comment count to the items. This seems to be a common problem and I tend to think there should be some nicer way of doing this job than brute force.
So please share your thoughts. How would you "populate" the Comment count to the Items?
check the MongoDB documentation and look for the method findAndModify() -- with it you can atomically update a document, e.g. add a comment and increment the document counter at the same time.
findAndModify
The findAndModify command atomically modifies and returns a single document. By default, the returned document does not include the modifications made on the update. To return the document with the modifications made on the update, use the new option.
Example
Use the update option, with update operators $inc for the counter, and $addToSet for adding the actual comment to an embedded array of comments.
db.runCommand(
{
findAndModify: "item",
query: { name: "MyItem", state: "active", rating: { $gt: 10 } },
sort: { rating: 1 },
update: { $inc: { commentCount: 1 },
$addToSet: {comments: new_comment} }
}
)
See:
MongoDB: findAndModify
MongoDB: Update Operators
I did some research on this issue and came up with following results. First, MongoDB docs suggest:
In general, use embedded data models when:
you have “contains” relationships between entities.
you have one-to-many relationships where the “many” objects always appear with or are viewed in the context of their parent documents.
So in my situation, it makes much more sense if Comments are embedded into Items, instead of having independent existence.
Nevertheless, I was curious to know the solution without changing my data model. As mentioned in MongoDB docs:
Referencing provides more flexibility than embedding; however, to
resolve the references, client-side applications must issue follow-up
queries. In other words, using references requires more roundtrips to
the server.
As multiple roundtrips are kosher now, I came up with following solution:
var showList = function(req, res){
// first DB roundtrip: fetch all items
return Item.find()
.exec(function(err, items) {
// second DB roundtrip: fetch comment counts grouped by item ids
Comment.aggregate({
$group: {
_id: '$item',
count: {
$sum: 1
}
}
}, function(err, agg){
// iterate over comment count groups (yes, that little dash is underscore.js)
_.each(agg, function( itr ){
// for each aggregated group, search for corresponding item and put commentCount in it
var item = _.find(items, function( item ){
return item._id.toString() == itr._id.toString();
});
if ( item ) {
item.set('commentCount', itr.count);
}
});
// send items to the client in JSON format
return res.send(items);
})
});
};
Agree? Disagree? Please enlighten me with your comments!
If you have a better answer, please post here, I'll accept it if I find it worthy.

Resources