简体   繁体   中英

mongoDB $unset each object that matches id in array

Here is how my documents look like:

{
  id: 123,
  tasks: {
    5f6effae74a3802fe80d02a4: Object
    5f6f289b73cc4e43546733bb: Object
    5f6f28d873cc4e43546733bc: Object
    5f6f291073cc4e43546733bd: Object,
    5f6f291073cc4e43541211cc: Object,
    5f6f291073cc4e43465662eq: Object
  },
  taskIds: [
    5f6effae74a3802fe80d02a4, 
    5f6f289b73cc4e43546733bb, 
    5f6f28d873cc4e43546733bc, 
    5f6f291073cc4e43546733bd
  ]
}

I need to delete each object in tasks that matches id from taskIds so I thought about mapping through taskIds like this:

const tasksDocument = await db.collection.findOne({id: 123})
tasksDocument.taskIds.map(async (id) => await tasksDocument.updateOne({ $unset: { [`tasks.${[id]}`]: "" } }))

But I'm wondering if there is cleaner way to do it without mapping?

If you're using Mongo version 4.2+ you can use pipelined update which allows you to use aggregation operators in an update.

Our strategy will be to convert the object to an array, filter it with the taskIds and then converting back to an object, we will achieve this by using operators like $arrayToObject , $objectToArray , $filter and more.

db.collection.update(
    {
        'id': 123
    },
    [
        {
            '$set': {
                tasks: {
                    $arrayToObject: {
                        $filter: {
                            input: {$objectToArray: '$tasks'},
                            as: 'task',
                            cond: {
                                $eq: [
                                    {
                                        $size: {
                                            $setIntersection: [['$$task.k'], '$taskIds']       
                                        }
                                    },
                                    0
                                ] 
                            }
                        }
                    }
                }
            }
        }
    ])

For older Mongo versions you have to split this into 2 calls and do it in code similar to your solution (just having one call to $unset instead of multiple).

const tasksDocument = await db.collection.findOne({id: 123});
let unsetArr = tasksDocument.taskIds.map(v => `tasks.${v}`);
await db.collection.updateOne({id: 123}, {$unset: unsetArr});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM