5
votes

I'd like to update a massive set of document on an hourly basis.

Here's the fairly simple Model:

class Article
   include Mongoid::Document
   field :article_nr, :type => Integer
   field :vendor_nr, :type => Integer
   field :description, :type => String
   field :ean
   field :stock
   field :ordered
   field :eta

so every hour i get a fresh stock list, where :stock,:ordered and :eta "might" have changed and i need to update them all.

Edit: the stocklist contains just

:article_nr, :stock, :ordered, :eta

wich i parse to a hash

In SQL i would have taken the route to foreign keying the article_nr to a "stock" table, dropping the whole stock table, and running a "collection.insert" or something alike

But that approach seems not to work with mongoid. Any hints? i can't get my head around collection.update and changing the foreign key on belongs_to and has_one seems not to work (tried it, but then Article.first.stock was nil)

But there has to be a faster way than iterating over the stocklist array of hashes and doing something like

Article.where( :article_nr => stocklist['article_nr']).update( stock: stocklist['stock'], eta: stocklist['eta'],orderd: stocklist['ordered'])
2

2 Answers

10
votes

UPDATING

You can atomically update multiple documents in the database via a criteria using Criteria#update_all. This will perform an atomic $set on all the attributes passed to the method.

 # Update all people with last name Oldman with new first name.
 Person.where(last_name: "Oldman").update_all(
first_name: "Pappa Gary"
 )

Now I can understood a bit more. You can try to do something like that, assuming that your article nr is uniq.

class Article
  include Mongoid::Document
  field :article_nr
  field :name
  key :article_nr

  has_many :stocks
end

class Stock
  include Mongoid::Document
  field :article_id
  field :eta
  field :ordered
  belongs_to :article
end

Then you when you create stock:

Stock.create(:article_id => "123", :eta => "200")

Then it will automaticly get assign to article with article_nr => "123" So you can always call last stock.

my_article.stocks.last

If you want to more precise you add field :article_nr in Stock, and then :after_save make new_stock.article_id = new_stock.article_nr

This way you don't have to do any updates, just create new stocks and they always will be put to correct Article on insert and you be able to get latest one.

0
votes

If you can extract just the stock information into a separate collection (perhaps with a has_one relationship in your Article), then you can use mongoimport with the --upsertFields option, using article_nr as your upsertField. See http://www.mongodb.org/display/DOCS/Import+Export+Tools.