MongoDB Mongoid 的 embedded_in 多层嵌入的自动保存是否存在问题?

lyfi2003 · 2012年02月09日 · 最后由 lyfi2003 回复于 2012年02月09日 · 4020 次阅读

有三个 Model, 如下:

class User
  include Mongoid::Document
  embeds_many :projects
end

class Project
  embedded_in :user
  embeds_many :tasks
end

class Task
  embedded_in :project
end

现在创建一下使用:

user = User.new
project = Project.new
task = Task.new
project.tasks << task
user.projects << project
user.save

然后查询: user.reload.projects[0].tasks 输出 [] task 并未保存,何故?按官方文档说明,这个嵌入方式会自动保存. 然而,project 保存成功,相关资料 stackoverflow 也没有,搜索查找源码暂未果. 我对 mongoid 处于模索中,不知各位有何见解?

帮你改了一下格式,你帖代码的用法不对,你在点击修改看看是怎么写的。

看用例没有问题,可以到 github issues 里面搜搜,如果没有结果就提交一个吧

@Rei 不知道有人有这种用法没?我现在不太习惯 has_many, belongs_to 了,用文档设计模式的话这种应该较为常见吧。

#4 楼 @lyfi2003 我会用 User has_many Project。Task 看情况,逻辑简单的话用 embed,复杂的话用 has_many。

# Append one or many child addresses, saving them if the person is persisted.
person.addresses << Address.new
person.addresses.push(Address.new)
person.addresses.concat([ address ])

那句注释的意思是,如果 person 已经 persisted 了,就会保存 addresses 你给出的例子里面,user 还没有 persisted,这样应该可以

user = User.create
project = Project.new
task = Task.new
project.tasks << task
user.projects << project

代码里也是这个意思 https://github.com/mongoid/mongoid/blob/master/lib/mongoid/relations/embedded/many.rb#L26

def <<(*args)
  docs = args.flatten
  return concat(docs) if docs.size > 1
  if doc = docs.first
    append(doc)
    doc.save if persistable? && !_assigning? #这里判断base如果persisted了,才会save
  end
end

def persistable?
  base.persisted? && !_binding?
end

#4 楼 @lyfi2003 has_many 和 embeds_many 应用的场合不一样

比如想看看 cqpx 这个 user 的注册时间是什么时候,可能会用类似这样的代码

u = User.find 'cqpx'
u.created_at

如果是user embeds_many topics,在执行上面这段代码的时候,会把 cqpx 发过的所有 topic 都从数据库里读出来,因为 topics 全都嵌在 User 表里。大量无用数据就会跟着被取出来。 如果是user has_many topics就没有这个问题

http://mongoid.org/docs/relations.html embeds_many 是 Embedded relations has_many 是 Referenced relations

Embedded relations are associations between one or many objects where the child object is embedded within the parent in the same document in the database. 
They can be extremely efficient when kept to a managable size in MongoDB since the total number of queries required to retrieve an entire object graph can be reduced to one.

Referenced relations are associations between documents that reside in separate collections in MongoDB. 
The link between the documents is handled similar to a relational database where a "foreign key" needs to be stored on one or both sides of the relation, but note that accessing a referenced relation required a separate query to the database since joins cannot be performed.

@cqpx 多谢你的解释。embeds_many 看来的场合更适合于解决关系数据库繁于处理的多层关联的问题。但又不是经常反复查询的数据. 不过,我想这正是 mongodb 对传统数据库的一个大的特点之一吧. 刚才的问题你的一些代码指引,我分析了觉得是一个 bug, 内部没有递归做 save 判定。给他们 mongoid 提一个 issues 先。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号