suku
suku

Reputation: 10929

Mongodb: How to add value to an array if value does not exist but update value if it does exist

Subdishes is a array in the item MajorFood. I want to add subdishes if they don't exist and update the subdishes if they do exist.

I tried the update method with addToSet. This works fine for a normal element but fails for an array.

                MajorFood.update({'_id' : majorFoodId, 'subdishes.food' : rowVals[0]},
                {$addToSet : {subdishes : {
                    food : rowVals[0],
                    energy : {
                        calories : s.getIntVal(rowVals[1]),
                        unit : rowVals[2]
                    }           
                }}}, {upsert : true}, function(err, doc){
                if(err){
                    s.l("err update" );
                    callback(err);
                    return;
                }
                s.l("success");
                callback(); 
            });

The update works fine when the value food already exists in subdishes. But it crashes when an element has to be added to the array.

I am getting the following error:

MongoError: Cannot apply $addToSet to a non-array field. 
Field named 'subdishes' has a non-array type Object

Is there a method to do this in a single function?

Upvotes: 1

Views: 1199

Answers (2)

chridam
chridam

Reputation: 103305

You won't be able to do this with a single atomic update. You can use the callback in the update function to check if there has been an update and push to array if not since the document does not exist:

MajorFood.update(
    { 
        "_id": majorFoodId,
        "subdishes.food" : rowVals[0]
    },
    { 
        "$set": {
            "subdishes.$": {        
                //without $ you get the error The dotted field is not valid for storage     
                "energy.$.calories": s.getIntVal(rowVals[1]),
                "energy.$.unit": rowVals[2]
            } 
       }
    },
    function(err, numAffected, rawResponse) {
        console.log(numAffected);
        console.log(rawResponse);
        if (!numAffected) {
            /* Push to array if subdish doesn't exist hence there's no update */
            MajorFood.update(
                { "_id": majorFoodId }
                { 
                    "$push": { 
                        "subdishes": {
                            "food": rowVals[0],
                            "energy": {
                                "calories": s.getIntVal(rowVals[1]),
                                "unit": rowVals[2]
                            } 
                        }
                    }
                },
                function(err, numAffected) {
                    if(err){
                        s.l("err update" );
                        callback(err);
                        return;
                    }
                    s.l("success");
                    callback(); 
                }
            );
        }            

    }
);

Upvotes: 1

Sourbh Gupta
Sourbh Gupta

Reputation: 833

May be this link can help you : mongodb addToSet a non-array field

   MajorFood.update({'_id' : majorFoodId, 'subdishes.food' : {$in:[rowVals[0]]}},
            {$addToSet : {subdishes : {
                food : rowVals[0],
                energy : {
                    calories : s.getIntVal(rowVals[1]),
                    unit : rowVals[2]
                }           
            }}}, {upsert : true}, function(err, doc){
            if(err){
                s.l("err update" );
                callback(err);
                return;
            }
            s.l("success");
            callback(); 
        });

Upvotes: 0

Related Questions