Is there a way to have an Update method remove the parent field if the result of the $unset operators results in an empty embedded document

Viewed 79

Assuming I have the following document in MongoDB:

{
    _id: 1,
    answer: 42,
    parent: {
        lock: true
    }
}

After running

updateOne({_id: 1}, {$unset: {'parent.lock': ""}});

The document becomes:

{
    _id: 1,
    answer: 42,
    parent: {}
}

Is there a way to have the 'parent' field also be removed only if the result of the update comment is an empty object other than making a second call?

In other words, I want the original doc to become:

{
    _id: 1,
    answer: 42
}

However, if the embedded document of the parent field also had other fields (was originally):

{
    _id: 1,
    answer: 42,
    parent: {
        lock: true,
        child: 'other'
    }
}

Then the result of the update command would be:

{
    _id: 1,
    answer: 42,
    parent: {
        child: 'other'
    }
}
1 Answers

This can be done with update aggregate pipelines:

updateOne({_id: 1}, [
    // Remove the desired field(s).
    // Note different syntax from original command
    { $unset : [ 'parent.lock' ] },
    
    // If the parent is now an empty document, then mark it to be removed, otherwise, set it equal to itself
    { $addFields: { parent: { $cond: {
        if: { $eq: [ '$parent', {}] },
        then: '$$REMOVE',
        else: '$parent'
    }}}} 

    // Short-hand notation of $cond command above:
    // { $addFields: { parent: { $cond: [ {$eq: [ '$parent', {}] }, '$$REMOVE', '$parent' ] }}} 
])

If anybody else has a better/more optimal proposal, please recommend.

Related