3

I'm trying to find a way to update a single array item using mongoid. I'm using Rails 4 and Mongodb.

My model looks like this

class User
  include Mongoid::Document
  include Mongoid::Timestamps

field :my_book_list, type: Array, default: []
field :book_name, type: String

I'm able to add entry to the array field using the following code:

User.where(id: self.user_id).add_to_set("my_book_list" => self.book_name)

After I have added data to the array, in the database it looks like this

db.collection.users 
{
    "_id" : ObjectId("56e09d54a0d00b0528000001"),
    "status" : true,
    "sign_in_count" : 3,
    "my_book_list" : 
     ["Learning Ruby", "MongoDB for Dummies"]

}

What I'm struggling with is to find a Rails / Mongoid way of updating the value of an item in the array by looking for the name.

Simply put, how do I change the value of my_book_list[1] by searching for it through name and not knowing its index. In this case index 1 is "MongoDB for Dummies" and needs to be updated to "MongoDB". So that the "my_book_list" array field looks like this after its updated:

db.collection.users 
{
    "_id" : ObjectId("56e09d54a0d00b0528000001"),
    "status" : true,
    "sign_in_count" : 3,
    "my_book_list" : 
     ["Learning Ruby", "MongoDB"]

}

How do I achieve this ?

1
  • Well the same thing in the underyling driver is achived by the inequality condition on the array element { "_id": ObjectId("56e09d54a0d00b0528000001"), "my_book_list": { "$ne": "Leaning Ruby" } },{ "$push": { "my_book_list": "Learning Ruby" } }, with the differnce being that not only is the element not added where it already exists, but it does so because the condition that it does not exist does not match anything to update. That's the distinction, but it's really unclear what you actually need or why the $addToSet used does not suit your purpose. Commented Mar 10, 2016 at 1:14

2 Answers 2

5

Instead of updating, think of it as adding & removing. You can use pull (https://docs.mongodb.org/ecosystem/tutorial/mongoid-persistence/#atomic)

Where your add to set uniquely adds it to an array, pull removes it based on the name. So assuming this:

user = User.find_by(id: self.user_id)

user.add_to_set(my_book_list: 'First Story')
p user.my_book_list
=> ['First Story']

user.add_to_set(my_book_list: 'Second Story')
p user.my_book_list
=> ['First Story', 'Second Story']

user.add_to_set(my_book_list: 'Third Story')
p user.my_book_list
=> ['First Story', 'Second Story', 'Third Story']

user.pull(my_book_list: 'Second Story')
p user.my_book_list
=> ['First Story', 'Third Story']

If you had duplicates in the set you can use pull_all, but you are using add to set so you won't need to.

Sign up to request clarification or add additional context in comments.

Comments

-2

This was more of a conceptual problem being a ruby beginner. The answer lies that mongo arrays are simple ruby array and we can use standard ruby methods to update the array.

In this case in my rails console I did this and it worked. The second line finds the array item and replaces with the new wird,

     u = User.first
     u.my_book_list.map! { |x| x == "MongoDB for Dummies" ? "MongoDB": x}
     u.save

1 Comment

It's always advised to make use of the mongodb operations you have at your disposal as opposed to relying on ruby. Using mongodb operations will always be much faster than ruby. (this applies to using SQL vs ruby as well in the case of relational databases)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.