Question

findAndModify in mongodb is great, but I am having a little trouble knowing which embedded document I modified.

Here is an example where a Post embeds_many Comments. (I'm using Mongoid ORM but the question is generic to any MongoDB setup).

begin
  p = Post.asc(id).where(comments: { '$elemMatch' => {reserved: false} }).find_and_modify({'$set' => {'comments.$.reserved' => true}}, {new: true}
  # now i need to find which comment I just reserved
  c = p.comments.select{|c| c.reserved }.first
  ...
ensure
  c.update_attribute :reserved, false
end

Ok this sort of works, but if I have multiple processes running this simultaneously my select could choose a comment that another process had reserved (race condition).

This is the closest I have for now (reserving by process id):

begin
  p = Post.asc(id).where(comments: { '$elemMatch' => {reserved: nil} }).find_and_modify({'$set' => {'comments.$.reserved' => Process.pid}}, {new: true}
  # now i need to find which comment I just reserved
  c = p.comments.select{|c| c.reserved == Process.pid }.first
  ...
ensure
  c.update_attribute :reserved, nil
end

Which seems to work. Is this the best way to do this or is there a better pattern?

Was it helpful?

Solution

Was able to solve it by generating a SecureRandom.hex and setting this on the embedded document with find_and_modify. Then you can loop through the embedded documents and see which one has your matching hex, to see which one you are working with.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top