add an attachment to a document in couch db using nodejs - node.js

I want to update an existing document in couchdb. I have an image and i want to add it to an existing document in the db without lose the previus fields.
I'm using nodejs with nano.
tanks, this put me in the right orientation. At the end i do it in this way:
db.get(id,{ revs_info: true }, function (error, objeto) {
if(error)
console.log('wrong id');
fs.readFile('image.jpg', function(err, data)
{
if (!err)
{
db.attachment.insert(id, 'imagen.jpg', data, 'image/jpg',{ rev: objeto._rev}, function(err, body) {
if (!err)
console.log(body);
});
}
});
});

Your question is not really clear about the specific problem. So here just some general guidance on updating documents.
When designing the database make sure you set the ID rather than allowing couchdb to edit it. This way you can access the document directly when updating it.
When updating, you are required to prove that you are updating the most recent version of the document. I usually retrieve the document first and make sure you have the most recent '_rev' in the document you'll insert.
finally the update may fail if a different process has edited the document in the time between retrieving and updating it. So you should capture a failure in the insert and repeat the process until you succeed.
That being said, there are two ways you can store an image:
As an attachment: I believe nano support the attachment.insert() and attachment.get() functions to do so.
As a reference: I would usually rather store the images elsewhere and just store the url or filepath to access them. I've not used nano much but believe you can do this by doing the below.
doc = db.get(docname); // get the document with all existing elements
doc['mynewimage'] = myimageurl; // update the document with the new image
// this assumes it's a dictionary
db.insert(doc); // inserts the document with the correct _id (= docname)
// and _rev

Related

Nodejs, MongoDB concurrent request creates duplicate record

Let me be real simple. I am running node.js server. When I receive data from patch request, first I need to check in database. If the row exists I will update it, otherwise I will create that record. Here is my code. This is what I am calling in the request handler callback.
let dbCollection = db$master.collection('users');
createUser(req.body).then(user => {
dbCollection.updateMany(
{ rmisId: req.body.rmisId },
{ $set: { ...user } },
{ upsert: true }
).then((result) => {
log.debug("RESULTS", user);
return result;
})
.catch((err => {
log.debug(err);
return err;
}));
})
This is working fine in sequential requests. But its creating duplicate record when I receive 10 concurrent request. I am running on my local machine and replicating concurrent request using Apache JMeter. Please help me if you have experienced this kind of problem.
Thank you !
UPDATE
I have tested another approach that reads the database like dbCollection.find({rmisId: req.body.rmisId}) the database for determine its existing or no. But it has no difference at all.
You cannot check-and-update. Mongodb operations are atomic at the document level. After you check and see that the record does not exist, another request may create the document you just checked, and after that you can recreate the same record if you don't have unique indexes or if you're generating the IDs.
Instead, you can use upsert, as you're already doing, but without the create. It looks like you're getting the ID from the request, so simply search using that ID, and upsert the user record. That way if some other thread inserts it before you do, you'll update what the previous thread inserted. If this is not something you prefer, add a unique index for that user ID field.

Update many objects, create if not exist

I'm working with a mean application and one of it functions is to do upload of csv files and convert it to json and persist in a mongodb database. But even month i receive a csv with new records and records that already exists (with new informations or not) in the database. Summing up, i need to update many objects and create it if not exist. My question is, what is the better way to do this, because these files are very large.
The current version just create these records like this:
Patient.create(records ,function(err, records) {
if (err){
res.send(err);
console.log(err);
}
res.json(records);
});
You can do this by following some simple steps
At Node JS use parse CSV to convert CSV into JSON
Then take all the data from collection and compare it with the new data.
For Comparison of data you can use lodash library, it's method is really fast.
Once you got the _id of the data which is new or need to be update. You can use the below query
db.collectionName.update({$in:{"_id":ids}},{$set:{"key":"value"}},{upsert:true, multi:true},function(err,doc){
console.log(doc)
})
don't forget to add upsert true because you have new data also.
Hope it Help!!

How to Determine if a Document was Actually Changed During Update in MongoDB

I am using the Mongoose driver with NodeJS. I have quite a simple update call whose purpose is to sync an external source of meetings to my database:
collection.update({ meeting_id: doc.meeting_id}, newDoc, {upsert:true})
The object returned determines whether or not an update or an insert occurred. This works perfectly. My issue is that I must determine if an actual change occurred. When you update a document with itself, MongoDB treats this in exactly the same way as if all fields were changed.
So my question is: Is there any good way to tell if anything actually changed? I could search for each document then compare each field manually, but this seems like a poor (and slow) solution.
you can use findAndModify which will return updated results as compared to update which will return no of updated records.
collection.findAndModify(
{ meeting_id: doc.meeting_id},
newDoc,
{ new: true },
function (err, documents) {
res.send({ error: err, affected: documents });
}
);

Preventing concurrent access to documents in Mongoose

My server application (using node.js, mongodb, mongoose) has a collection of documents for which it is important that two client applications cannot modify them at the same time without seeing each other's modification.
To prevent this I added a simple document versioning system: a pre-hook on the schema which checks if the version of the document is valid (i.e., not higher than the one the client last read). At first sight it works fine:
// Validate version number
UserSchema.pre("save", function(next) {
var user = this
user.constructor.findById(user._id, function(err, userCurrent) { // userCurrent is the user that is currently in the db
if (err) return next(err)
if (userCurrent == null) return next()
if(userCurrent.docVersion > user.docVersion) {
return next(new Error("document was modified by someone else"))
} else {
user.docVersion = user.docVersion + 1
return next()
}
})
})
The problem is the following:
When one User document is saved at the same time by two client applications, is it possible that these interleave between the pre-hook and the actual save operations? What I mean is the following, imagine time going from left to right and v being the version number (which is persisted by save):
App1: findById(pre)[v:1] save[v->2]
App2: findById(pre)[v:1] save[v->2]
Resulting in App1 saving something that has been modified meanwhile (by App2), and it has no way to notice that it was modified. App2's update is completely lost.
My question might boil down to: Do the Mongoose pre-hook and the save method happen in one atomic step?
If not, could you give me a suggestion on how to fix this problem so that no update ever gets lost?
Thank you!
MongoDB has findAndModify which, for a single matching document, is an atomic operation.
Mongoose has various methods that use this method, and I think that they will suit your use case:
Model.findOneAndUpdate()
Model.findByIdAndUpdate()
Model.findOneAndRemove()
Model.findByIdAndRemove()
Another solution (one that Mongoose itself uses as well for its own document versioning) is to use the Update Document if Current pattern.

Updating and Deleting documents using NodeJS on Cloudant DB

I was able to successfully query(select) and insert data into Cloudant database using HTTP /REST API. But I am not able to figure out - how to delete and modify documents.
For Delete: I tried the following code in nodejs
path : '/quick_loan_nosql_db_1?951b05d1b6aa100f4b94e5185674ef40/_rev=1-88963c755157188091f0d30115de18ce'
part of the REST API Request with METHOD: DELETE.
But when I execute it deletes the entire database instead of the ID being specified.
For Update: Can some one provide a sample, I tried with PUT, but in response I got a Conflict data error.
Any input would be appreciated.
Nice! To answer your original question, you just have the "/" and the "?" in the wrong places. To recap:
/quick_loan_nosql_db_1?951b05d1b6aa100f4b94e5185674ef40/_rev=1-88963c755157188091f0d30115de18ce
should instead be:
/quick_loan_nosql_db_1/951b05d1b6aa100f4b94e5185674ef40?_rev=1-88963c755157188091f0d30115de18ce
Here is one way I figured out to perform the Update and Delete.
I used nano api:
Include nano by
var nano =require('nano')('https://'+dbCredentials.user+':'+dbCredentials.password+'hostname:port/');
Please make sure to put the right user id and password
For Update
Update - you need to use insert api only, but with the right _id and _eval and the changes. For example:
nanodb.insert({ "_id": "3a1cc8c7f955f895131c3289f5144eab", "_rev": "2- 7040205a1c9270ad696724458399ac94", "name": "Tom", "employername":"Google"}, function(err, body, header) {
if (err) {
console.log('[db.insert] ', err);
return;
}
console.log('you have inserted the rabbit.')
console.log(body);
});
The above code will perform an update on the given id and the _rev. There will be a new revision number updated and the id will remain same. If you miss the ID or revision number, it will throw a conflict error.
For Delete
Simple use nano.destroy with the id and the revision number
nanodb.destroy("3a1cc8c7f955f895131c3289f5144eab","3-3e39e2298f109414cef1310449e0fd5c",function(err, body, header) {
if (err) {
console.log('[db.insert] ', err);
return;
}
console.log('you have inserted the rabbit.')
console.log(body);
});
Using Nano like framework API is better than making REST API calls over http for accessing the cloudant Database.
Hope this helps for people who want to connect to Cloudant db from NodeJS

Resources