Search code examples
node.jsmongodbmongodb-update

MongoDB update query to unset specific array members based on the value


I have an array of sub-document like below


    /* record 1 */
        {
                        "_id" : "462044",
                        "program" : [ 
                                {
                                    "name" : "Business Services"
                                }, 
                                {
                                    "name" : "Homeland Security"
                                }, 

                                {
                                    "title" : [ 
                                        "associate"
                                    ],
                                    "name" : "Engineering"
                                }, 

                                {
                                    "title" : [ 
                                        "associate"
                                    ],
                                    "name" : "Computer Software"
                                }
                                ]

            }

    /* record 2 */
            {
                        "_id" : "462045",
                        "program" : [ 
                                {
                                    "name" : "Business Services"
                                }, 
                                {
                                    "name" : "Homeland Security"
                                }, 

                                {
                                    "title" : [ 
                                        "associate"
                                    ],
                                    "name" : "Engineering"
                                }, 

                                {
                                    "title" : [ 
                                        "associate"
                                    ],
                                    "name" : "Computer Software"
                                }
                                ]

            }      

[I want to delete array members which do not have 'title' sub-members]

How can I write mongo update query or a nodejs function to get the following document set


    /* record 1 */
        {

                        "_id" : "462044",
                        "program" : [ 

                                {
                                    "title" : [ 
                                        "associate"
                                    ],
                                    "name" : "Engineering"
                                }, 

                                {
                                    "title" : [ 
                                        "associate"
                                    ],
                                    "name" : "Computer Software"
                                }
                                ]

        }


    /* record 2 */
        {
                        "_id" : "462045",
                        "program [
                                {
                                    "title" : [ 
                                        "associate"
                                    ],
                                    "name" : "Engineering"
                                }, 

                                {
                                    "title" : [ 
                                        "associate"
                                    ],
                                    "name" : "Computer Software"
                                }
                                ]

        }      


Solution

  • Well, first of all your document structure looks very odd. Every record have a different field representing essentially same information, in your case school1 and school2.

    It can easily be fixed if you renamed those fields to just school.

    Provided that you fix your document structure, you can easily eliminate desired sub documents with help of aggregation framework and plain update queries.

    Example:

    db.collection.aggregate([
      {
        $project: {
          school: {
            $filter: {
              input: "$school.program",
              as: "prog",
              cond: {
                $ne: [
                  {
                    $ifNull: [
                      "$$prog.title",
                      true
                    ]
                  },
                  true
                ]
              }
            }
          }
        }
      }
    ]).forEach(function(o){
      db.collection.updateOne({
        _id: o._id
      },
      {
        $set: {
          school: o.school
        }
      });
    })
    

    This will turn your old document to (removing all sub fields form program not containing title:

    { 
        "_id" : ObjectId("57371cdf81e9959ba1a5fab0"), 
        "school" : [
            {
                "title" : [
                    "associate"
                ], 
                "name" : "Engineering"
            }, 
            {
                "title" : [
                    "associate"
                ], 
                "name" : "Computer Software"
            }
        ]
    }
    { 
        "_id" : ObjectId("57371cdf81e9959ba1a5fab1"), 
        "school" : [
            {
                "title" : [
                    "associate"
                ], 
                "name" : "Engineering"
            }, 
            {
                "title" : [
                    "associate"
                ], 
                "name" : "Computer Software"
            }
        ]
    }