Coeus
Coeus

Reputation: 2615

MEAN: unable to update data to DB

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

Answers (1)

Soubhik Mondal
Soubhik Mondal

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

Related Questions