How to do an upsert / push with mongoid / moped
Asked Answered
H

3

9

I'm using Mongoid (v3) to access MongoDB, and want to perform this action:

db.sessionlogs.update( 
    {sessionid: '12345'}, /* selection criteria */
    {'$push':{rows: "new set of data"}},  /* modification */
    true /* upsert */
);

This works fine in the mongo shell. It's also exactly what I want since it's a single atomic operation which is important to me as I'm going to be calling it a lot. I don't want to have to do two operations -- a fetch and then an update. I've tried a bunch of things through mongoid, but can't get it to work.

How can I get MongoID out of the way and just send this command to MongoDB? I'm guessing there's some way to do this at the Moped level, but the documentation of that library is basically non-existent.

Hardin answered 18/7, 2012 at 17:39 Comment(1)
Did you see the Moped Driver docs?African
H
10

[Answer found while writing the question...]

criteria = Sessionlogs.collection.find(:sessionid => sessionid)
criteria.upsert("$push" => {"rows" => datarow})
Hardin answered 18/7, 2012 at 17:39 Comment(0)
A
2

Here is one way to do it:

session_log = SessionLog.new(session_id: '12345')
session_log.upsert
session_log.push(:rows, "new set of data")

Or another:

SessionLog.find_or_create_by(session_id: '12345').
  push(:rows, "new set of data")

#push performs an atomic $push on the field. It is explained on the Atomic Persistence page.

(Note: the examples use UpperCamelCase and snake_case as is Ruby convention.)

African answered 28/7, 2012 at 5:3 Comment(0)
B
0

Don't go down to moped just yet, you can use find and modify operation to achieve the same thing (with all the default scope and inheritance goodies)

Sample to save an edge in a graph if not existed

edge = {source_id: session[:user_id],dest_id:product._id, name: edge_name}
ProductEdge.where(edge).find_and_modify(ProductEdge.new(edge).as_document,{upsert:true})
Brodench answered 4/1, 2014 at 19:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.