MongoDB updating arrays (pull all matching elements and pull one matching element)

I am currently writing an availabilities system in a MongoDB document but I can’t seem to figure out how to make my specific update (pull one element and all elements depending on the arrays) in one request to be atomic (it needs to be so).

The document has a slots object which contains services and each services contain slots to be picked and thus pulled. It looks like this :

{
    "dayId": 21055,
    "modificationId": {
        "$oid": "6036f8c341b05c730a93439f"
    },
    "slots": {
        "serviceA": [{
            "startDate": {
                "$date": "2021-02-23T10:00:00.000Z"
            },
            "endDate": {
                "$date": "2021-02-23T12:00:00.000Z"
            },
            "duration": 120
        }],
        "serviceB": [{
            "startDate": {
                "$date": "2021-02-23T10:00:00.000Z"
            },
            "endDate": {
                "$date": "2021-02-23T11:00:00.000Z"
            },
            "duration": 60
        }, {
            "startDate": {
                "$date": "2021-02-23T11:00:00.000Z"
            },
            "endDate": {
                "$date": "2021-02-23T12:00:00.000Z"
            },
            "duration": 60
        }],
        "serviceC": [{
            "startDate": {
                "$date": "2021-02-23T10:00:00.000Z"
            },
            "endDate": {
                "$date": "2021-02-23T10:30:00.000Z"
            },
            "duration": 30
        }, {
            "startDate": {
                "$date": "2021-02-23T10:30:00.000Z"
            },
            "endDate": {
                "$date": "2021-02-23T11:00:00.000Z"
            },
            "duration": 30
        }, {
            "startDate": {
                "$date": "2021-02-23T11:30:00.000Z"
            },
            "endDate": {
                "$date": "2021-02-23T12:00:00.000Z"
            },
            "duration": 30
        }]
    }
}

The catch is some services need to have all their elements removed according to a complex condition on their dates and duration except one service only the first condition matching element.

I’ve come up with this (the duration equality is normally replaced by $lte, $gte and so on…)

        db.availabilities.update(
          { "_id": ObjectId("6037396b41b057730a8343a3") },
          { $pull: { "slots.serviceA": { duration: 120 },
         "slots.serviceB": { duration: 60 },
         "slots.serviceC": { duration: 30 } } 
        }
        );

For the more complex condition I intended to do it this way but on the dates too/instead (it seems to be working just fine) :

"slots.serviceC": { $and: [ { "duration": { $gte: 30 } }, { "duration": { $lte: 60 } } ] }

So I’d like service A and service B to pull all the matching elements and ONLY ONE for service C for example.

Thanks in advance for the help,

document on compass for readability

Hi @GUIGAL_Allan,

Welcome to make MongoDB community.

Not sure I got the problem. Do you face any error with the $pull .

Can’t you use several $pull for each service?

https://docs.mongodb.com/manual/reference/operator/update/pull/#remove-items-from-an-array-of-documents

If you need to do a dynamic condition on an array consider using array filters:
https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/

Thanks,
Pavel