2016-09-07 3 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

나는 루비에 익숙하지 않다. 그러나 나는 그 문제를 이해하고 있다고 생각한다. 스키마가 다음과 같이 보일 수 있습니다.

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) 발견했을 때 주어진 필드를 업데이트의 user_id에 대해 일치

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

또는없는 경우 새로 만듭니다.

이 작업을하려면 마지막으로 중요한 단계가 하나 있습니다. 특수 플래그를 사용하여 Address 컬렉션에 인덱스를 추가해야합니다.

(이 경우 user_id) 다음은에 쿼리하는 필드 는 { unique: true } 또는 { sparse: true } 중 하나의 국기와 색인을해야합니다. unique 플래그가 두 개 이상일 경우 오류가 발생합니다. user_id 필드. sparse 옵션이 없습니다. 값이 0 일 수도 있다고 생각하면 사용하십시오.터미널을 통해

액세스하여 몽고 DB를

  1. show dbs
  2. use your_db_name 확인 주소 수집은 이미
  3. db.addresses.getIndexes() 이미 USER_ID에 인덱스가 있는지 찾고있는 인덱스가있는 경우, 이를 제거하고 db.addresses.dropIndex({ user_id: 1}) 플래그를 사용하여 다시 만들고 다음 플래그를 사용하여 다시 만들 수 있습니다.
  4. https://docs.mongodb.com/manual/reference/method/db.collection.update/

  5. db.addresses.createIndex({ user_id: 1}, { sparse: true })
편집 번호는 Mongoid 5에 변경 사항이있는 것 같다 1

.. 대신 User.collection.update의 당신은 워드 프로세서 당신을 보여 User.collection.update_one

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

사용할 수 있습니다 fi로 query 대신 filter이 필요합니다. 첫 번째 인수 있지만 .. 같은 것 같다

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

PS : 당신 만 update operator 같은 $set를 포함하지 않고 업데이트 절과 같은 { "address": 'the_address' }를 작성하는 경우 는 전체 문서가 아니라 단지 address을 수정하지 않고 덮어 얻을 것이다 들.

편집 # 당신이 링크 울부 짖는 소리에 upsert 절을 보면, 당신은 볼 수 unique 또는

sparse으로 인덱싱 할 수있는 이유에 대해 2

:

하는 것은 방지하기 위해 여러 upserts는 필터 필드가 고유하게 색인되어 있는지 확인합니다.

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

+0

왜 고유 또는 희소 인덱스가 필요합니까? –

+0

당신은 그 키에 대해'update' 또는 찾지 못했다면'insert'에 매치 할 것이기 때문에 당신은 그 키와 일치 할 것입니다. 고유 한 색인이나 희소 색인이없는 경우에도 일치하는 첫 번째 문서를 업데이트하거나 일치하는 모든 문서를'{multi : true} '플래그로 업데이트 할 수 있습니다. 편집 # 2를 참조하십시오. – Shiyason

+0

고유 한 값을 보장하기 위해 인덱스가 필요하지 않습니다. –