每个用户都有一个地址。
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 :(得分: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})
答案 1 :(得分: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
)或在找不到时创建新字段。
为了实现这一点,尽管有最后一个关键步骤。 您必须使用特殊标志向Address集合添加索引。
您要查询的字段(在这种情况下为user_id
)
必须使用{ unique: true }
的标记编入索引
或{ sparse: true }
。 unique
标志会引发错误
如果您有2个或更多nil user_id
个字段。 sparse
选项不会。
如果您认为自己可能没有值,请使用它。
通过终端访问您的mongo数据库
show dbs
use your_db_name
检查地址集合是否已具有您要查找的索引db.addresses.getIndexes()
如果它已经有user_id的索引,您可能想要删除它
db.addresses.dropIndex( { user_id: 1} )
并使用以下标志再次创建它: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/
文档显示您需要filter
而不是query
作为第一个参数,但它们似乎是相同的。
Address.collection.update_one( { user_id: user_id },
'$set' => { "address": 'the_address', upsert: true} )
PS:
如果您只将{ "address": 'the_address' }
作为更新条款而不包含update operator
,例如$set
,则整个文档将被覆盖,而不是只更新address
字段。
EDIT#2
关于您可能希望使用unique
或sparse
如果您查看以下链接中的upsert
部分,您会看到:
要避免多次upsert,请确保过滤器字段是唯一的 索引。
https://docs.mongodb.com/manual/reference/method/db.collection.updateOne/