Update several documents of the same type with different values

Hello All!

I have several documents of the same type that I would like to update at the same time, as well a couple of other operations that I am looking to do within a transaction using the Swift driver.

This is the code I currently have below, but I am stuck on what would be the best way to update several of the same documents? I need to $inc a field by 1 for all of them and then the tricky part is updating another field with their own specific values.

Should I loop through them one at time and use the updateOne operator? Is there a better way to do this?

return req.application.mongoClient.withSession { session in
    return session.startTransaction().flatMap { _ -> EventLoopFuture<InsertManyResult?> in
        req.playerRatingsCollection.insertMany(playerRatings, session: session)
    }
    .flatMap { _ -> EventLoopFuture<InsertManyResult?> in
        req.memberPlayerRatingsCollection.insertMany(Array(insertNewMemberPlayerRatings), session: session)
    }
    .flatMap { _ -> EventLoopFuture<UpdateResult?> in
        // several documents where I need to $inc a totalRaitngs fields by 1 and update the average ratings for each document
        req.memberPlayerRatingsCollection.updateMany(filter: <#T##BSONDocument#>, update: <#T##BSONDocument#>)
    }
    .map { _ in
        Response(status: .ok)
    }
}
.hop(to: req.eventLoop)

Please let me know if anything doesn’t make sense or needs further clarity. I’ve looked into several different ways of solving the problem I am stuck on using change streams and views but I’ve found them both quite complex and would ideally like to use the above approach.

Thanks

Hi @Piers_Ebdon,

So if I understand correctly you want to avoid the need of fetching the updated documents before the update, otherwise I think doing a single document math calculations might be easier on the client side saving the calculated values directly.

If you still want to do it server side I would recommend looking into pipeline updates available from MongoDB 4.2 .
https://docs.mongodb.com/manual/tutorial/update-documents-with-aggregation-pipeline/

You can filter the needed documents and run few stages on each. Since I don’t know the specific of your logic and documents i would say it should look like:

[ Stage 1 - update the total ratings by inc 1,
Stage 2 - calculate the avg based on the totalRatings from previous stage and update
]

Best
Pavel

Hi @Pavel_Duchovny

Thanks for the response.

The document model I am trying to update is:

struct MemberPlayerRating: Content {
    var _id: BSONObjectID?
    let averageRating: Double
    let totalRatings: Int
    let playerID: BSONObjectID
    let userID: BSONObjectID
}

So what I am unsure about is the best way to update say 5 different MemberPlayerRating documents with different new ratings in order to calculate their new average rating. I need them either to all fail or all succeed ideally.

so if I had the following data, which I would like to use to calculate the new averageRating for a MemberPlayerRating:

{ playerID: 1, newRating: 7, userID: 1 },
{ playerID: 2, newRating: 6.1, userID: 1 },
{ playerID: 3, newRating: 2, userID: 1 },
{ playerID: 4, newRating: 9, userID: 1 },
{ playerID: 5, newRating 4.7, userID: 1 }

Even if I calculated the averageRating client side, I would still then want to update all the averageRating at the same time for the different documents. I don’t think I can achieve this with updateMany or an aggregation pipeline. is that correct? if so is there a recommended way to do this?

Thanks

Hi @Piers_Ebdon,

If you want multiple document update to succeed or fail as one you should consider using transactions

https://docs.mongodb.com/manual/core/transactions/

Another option is to keep updated data in one document to update it as one.

An update with multi true will update all documents in one command but as it is not atomic as a whole it cannot guarantee that all will succeed or fail everything.

Best
Pavel

1 Like

Hi @Pavel_Duchovny

I think keep the updated data in one document is the way to go.

Thanks!!

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.