0

So far, after i tried, i came up with solution where i am able to remove the whole object inside of the array if that object has field with empty value. That does not work in my case. I only need to remove the field and keep rest of the object. In this case, "Comment" field is the one having empty values occasionally. Thanks in advance!

Structure:

someArray: [
    {
      field1:"value",
      field2:"value",
      Comment:"",
      Answer:"",
},
    {
      field1:"value",
      field2:"value",
      Comment:"",
      Answer:"",

}]

Code:

        $project: {
          someArray: {
            $filter: {
              input: "$someArray", as: "array",
              cond: { $ne: [ "$$array.Comment", ""]}}}}
8
  • Instead of $filter try using the $map operator. And, use $$REMOVE system variable to delete a field. Commented Jun 29, 2022 at 3:22
  • Do you want to update the document permanently or it is specific to a read operation? Commented Jun 29, 2022 at 3:37
  • I have tried, but it is removing the whole object if "Comment": "". Specific to read operation. Thank you! Commented Jun 29, 2022 at 3:44
  • if i use $map instead of $filter cond becomes unrecognized parameter Commented Jun 29, 2022 at 3:50
  • @prasad_ I think with $$REMOVE you an remove only entire fields but not single elements from an array. Commented Jun 29, 2022 at 4:55

3 Answers 3

1

Use $map to loop over the array elements.For each array element where comment is not an empty string, return whole element, otherwise return the document excluding comment field. Like this:

db.collection.aggregate([
  {
    "$project": {
      someArray: {
        $map: {
          input: "$someArray",
          as: "element",
          in: {
            $cond: {
              if: {
                $eq: [
                  "",
                  "$$element.Comment"
                ]
              },
              then: {
                field1: "$$element.field1",
                field2: "$$element.field2"
              },
              else: "$$element"
            }
          }
        }
      }
    }
  },
  
])

Here, is the working link.

Sign up to request clarification or add additional context in comments.

Comments

1

Here is a solution where an array's nested object can have multiple fields and these need not be referred in the aggregation. Removes the nested object's field with value as an empty string (""):

db.collection.aggregate([
{ 
  $set: { 
      someArray: { 
          $map: { 
              input: '$someArray', 
              as: 'e',
              in: {
                  $let: {
                      vars: {
                          temp_var: { 
                              $filter: { 
                                  input: { $objectToArray: '$$e' }, 
                                  cond: { $ne: [ '', '$$this.v' ] }, 
                              }
                           }
                      },
                      in: {
                          $arrayToObject: '$$temp_var'
                      }
                  }
              }
          }
      }
   }
},
])

3 Comments

Maybe better cond: {$not: {$and: [ {$eq: ["$$this.k", "Comment"]}, {$eq: ["$$this.v", ""]} ]}}
Maybe, if your data has other fields with empty values. Finally, its a matter of the requirement.
@WernfriedDomscheit To check for just one field only (in this case, Comment), use this for the cond: $or: [ { $ne: [ 'Comment', '$$this.k' ] }, { $and: [ { $eq: [ 'Comment', '$$this.k' ] }, { $ne: [ '', '$$this.v' ] } ] } ]
0

Solution from Charchit Kapoor works only if your array has exactly

{
  field1: ...
  field2: ...
  Comment:""
}

But it does not work for arbitrary fields. I was looking for more generic solution, my first idea was this:

db.collection.aggregate([
   {
      "$project": {
         someArray: {
            $map: {
               input: "$someArray",
               in: {
                  $cond: {
                     if: { $eq: ["$$this.Comment", ""] },
                     then: { $mergeObjects: ["$$this", { Comment: "$$REMOVE" }] },
                     else: "$$this"
                  }
               }
            }
         }
      }
   }
])

but it does not work.

I ended on this one:

db.collection.aggregate([
   {
      "$project": {
         someArray: {
            $map: {
               input: "$someArray",
               in: {
                  $cond: {
                     if: { $eq: ["", "$$this.Comment"] },
                     then: {
                        $arrayToObject: {
                           $filter: {
                              input: {
                                 $map: {
                                    input: { $objectToArray: "$$this" },
                                    as: "element",
                                    in: { $cond: [{ $eq: ["$$element.k", "Comment"] }, null, "$$element"] }
                                 }
                              },
                              as: "filter",
                              cond: "$$filter" // removes null's from array 
                           }
                        }
                     },
                     else: "$$this"
                  }
               }
            }
         }
      }
   }
])

Mongo Playground

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.