2016-09-07 26 views
0

每個用戶都有一個地址。在Mongoid中`update_or_initialize_with`的好方法是什麼?

class User 
    include Mongoid::Document 

    has_one :address 
end 

class Address 
    include Mongoid::Document 

    belongs_to :user 

    field :street_name, type:String 
end 

u = User.find(...) 
u.address.update(street_name: 'Main St') 

如果我們有一個沒有地址的用戶,這將失敗。

那麼,有沒有一個很好的(內置)的方式做u.address.update_or_initialize_with

Mongoid 5

回答

0

我不熟悉ruby。但我想我明白這個問題。你的模式可能看起來像這樣。

user = { 
    _id : user1234, 
    address: address789 
} 

address = { 
    _id: address789, 
    street_name: "" 
    user: user1234 
} 

//in mongodb(javascript), you can get/update address of user this way 
u = User.find({_id: user1234}) 
u.address //address789 
db.address.update({user: u.address}, {street_name: "new_street name"}) 

//but since the address has not been created, the variable u does not even have property address. 
u.address = undefined 

或許你可以嘗試只是手動創建和連接它像這樣:

#create an address document, to get _id of this address 
address = address.insert({street_name: "something"}); 

#link or attached it to u.address 
u.update({address: address._id}) 
0

最近我有這個問題。有一個內置的方式,但它不同於活動記錄'#find_or_initialize_by#find_or_create_by方法。

就我而言,我需要批量插入記錄並更新或創建如果沒有找到,但我相信同樣的技術即使你不是批量插入使用。

# returns an array of query hashes: 
def update_command(users) 
    updates = [] 
    users.each do |user| 
    updates << { 'q' => {'user_id' => user._id}, 
       'u' => {'address' => 'address'}, 
       'multi' => false, 
       'upsert' => true } 
    end 
    { update: Address.collection_name.to_s, updates: updates, ordered: false } 
end 

def bulk_update(users) 
    client = Mongoid.default_client 
    command = bulk_command(users) 
    client.command command 
    client.close 
end 

,因爲你沒有批量更新,假設你有你的地址集合稱爲user_id一個外鍵字段。你也許能夠:

Address.collection.update({ 'q' => {'user_id' => user._id}, 
          'u' => {'address' => 'address'}, 
          'multi' => false, 
          'upsert' => true } 

將匹配對user_id,更新給定的領域時發現(address在這種情況下),或創建一個新的未發現的時候。

對於這項工作,有1個雖然最後關鍵的一步。 您必須使用特殊標誌將索引添加到您的Address集合。

要查詢上的字段(user_id在這種情況下) 必須任{ unique: true }{ sparse: true }標誌索引。如果您有2個或更多無nil user_id字段,則unique標誌將產生錯誤 。 sparse選項不會。 如果您認爲您可能沒有任何值,請使用該值。通過終端

訪問您的蒙戈DB

  1. show dbs
  2. use your_db_name 檢查,如果該地址收集已經有您正在尋找
  3. db.addresses.getIndexes() 如果已經對user_ID的索引的索引,您可能想要刪除它 db.addresses.dropIndex({ user_id: 1}) 並使用以下標誌再次創建它:
  4. db.addresses.createIndex({ user_id: 1}, { sparse: true })

https://docs.mongodb.com/manual/reference/method/db.collection.update/

編輯#1

似乎有Mongoid 5的變化..而不是User.collection.update可以使用User.collection.update_one

https://docs.mongodb.com/manual/reference/method/db.collection.updateOne/

該文檔顯示你作爲fi需要一個filter而不是一個query第一個參數,但他們似乎是相同..

Address.collection.update_one({ user_id: user_id }, 
    '$set' => { "address": 'the_address', upsert: true}) 

PS: 如果你只寫{ "address": 'the_address' }爲您的UPDATE子句,而不包括update operator$set,整個文件將被覆蓋,而不是更新只是address領域。

編輯#2

關於爲什麼您可能希望索引與uniquesparse

如果你看一下在鏈接波紋管的upsert部分中,您將看到:

爲了避免多個upserts,確保過濾器字段是唯一的索引 。

https://docs.mongodb.com/manual/reference/method/db.collection.updateOne/

+0

爲什麼你需要一個獨特的或稀疏索引? –

+0

因爲你將匹配那個關鍵字來'更新'如果找到或'插入'如果沒有找到。如果你沒有一個唯一的或稀疏索引,你仍可以更新的第一個匹配的文件或用'更新所有匹配的文檔{多:真}'標誌。 請參閱編輯#2。 – Shiyason

+0

我不需要索引來確保唯一值。 –

相關問題