Reputation: 2615
Im trying to update data to mongodb through express, Though my api responds status 200, Im unable to update the values to mongoose, Im using mongoose skin
var mongo = require('mongoskin');
var db = mongo.db(config.connectionString, {
native_parser: true
});
var ObjectId = require('mongodb').ObjectID;
db.bind('users');
db.bind('dashboard')
function update(_id, userParam) {
var deferred = Q.defer();
for (var i = 0; i < Object.keys(userParam).length; i++) {
var set = {
file: userParam[i].file,
result: userParam[i].result,
user_id: userParam[i].user_id
};
db.dashboard.update({
_id: mongo.helper.toObjectID(_id)
}, {
$set: set
},
function(err, doc) {
if (err) deferred.reject(err);
deferred.resolve();
});
};
return deferred.promise;
}
My API
{
"0": {
"_id": "57396e49a6c36801024021a1",
"file": "app_static/audio/SampleAudio_0.4mb.mp3",
"result": "FM",
"user_id": "57396ded0aef5ee405320dbe"
},
"1": {
"_id": "57396e5ca6c36801024021a2",
"file": "app_static/audio/SampleAudio_0.7mb.mp3",
"user_id": "57396ded0aef5ee405320dbe"
}
}
I have have a for loop so that entire api is considered and been to push to mongodb
Please also do suggest any alternative to push entire json to mongodb..
Any help is much appreciated
Thanks in advance
Upvotes: 1
Views: 51
Reputation: 2666
db.dashboard.update
is an asynchronous (a.k.a. non-blocking) function which takes a callback
as an argument.
You are calling db.dashboard.update
multiple times (via the for
loop) but inside the callback
you are rejecting or resolving the same promise
.
This means, that the then
method of the returned promise
will be executed when the callback of the very first db.dashboard.update
is called.
For the rest of the update operations, your then
function won't be notified.
SOLUTIONS:
1
Put your asynchronous code inside an IIFE
and call your deferred.resolve
during the last iteration of the loop.
function update(_id, userParam) {
var deferred = Q.defer();
var length = Object.keys(userParam).length;
for (var i = 0; i < length; i++) {
var set = {
file: userParam[i].file,
result: userParam[i].result,
user_id: userParam[i].user_id
};
(function(set, i) { // <------------------------- enclosing everything in an IIFE
db.dashboard.update({
_id: mongo.helper.toObjectID(_id)
}, {
$set: set
},
function(err, doc) {
if (err) {
deferred.reject(err);
} else if (length - 1 === i) { // <-- checking if this is the last iteration
deferred.resolve();
}
});
})(set, i); // <--------------------------------- sharing set and i with the IIFE scope
};
return deferred.promise;
}
2
Use async.map
. (This is the more graceful way of doing it).
function update(_id, userParam) {
var deferred = Q.defer();
/**
* Array to contain all the
* @type {Array}
*/
var arrayOfSets = [];
/**
* Converting each key-value pair in userParam into an array element
* and pushing it into arrayOfSets
*/
for (var i in userParam) {
arrayOfSets.push({
file: userParam[i].file,
result: userParam[i].result,
user_id: userParam[i].user_id
});
}
/**
* Executing async.map
*
* Parameters:
*
* 1. arrayOfSets - each element will be fed to the function in the 2nd parameter
*
* 2. function(item, callback) - in this function do the update operation
*
* 3. function(err, result) - in this function resolve or reject the promise
*/
async.map(arrayOfSets, function(item, callback) {
db.dashboard.update({
_id: mongo.helper.toObjectID(_id)
}, {
$set: item
},
function(err, doc) {
if (err) {
callback(err, null);
} else {
callback(null, doc);
}
});
}, function(err, result) {
if (err) {
deferred.reject(err);
} else {
deferred.resolve(result);
}
});
return deferred.promise;
}
Also, else
code should always be enclosed in else
!
function(err, doc) {
if (err) {
deferred.reject(err);
} else { // always enclose in else!
deferred.resolve();
}
}
Upvotes: 1