0

每个用户都有一个地址。

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

蒙古五号

4

2 回答 2

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})
于 2016-09-07T20:20:16.040 回答
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在这种情况下)或在未找到时创建一个新字段。

为此,还有最后一个关键步骤。您必须使用特殊标志将索引添加到您的地址集合。

您要查询的字段(user_id在这种情况下)必须使用{ unique: true } or标志进行索引{ sparse: true }。如果您有 2 个或更多 nil字段,该unique标志将引发错误。user_idsparse选项不会。如果您认为您可能有 nil 值,请使用它。

通过终端访问您的 mongo 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/

文档显示您需要 afilter而不是 aquery作为第一个参数,但它们似乎是相同的..

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

PS:如果你只写{ "address": 'the_address' }你的更新子句而不包括一个update operator例如$set,整个文档将被覆盖,而不是只更新address字段。

编辑#2

关于您可能希望使用unique或索引的原因sparse

如果您查看upsert下面链接中的部分,您将看到:

为避免多次更新插入,请确保过滤器字段具有唯一索引。

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

于 2016-09-07T21:00:07.917 回答