mongodb指南
mongodb指南(翻译)(十四) - developer zone - 数据类型和约定(三)之数据库引用
由于mongodb是非关系型的(没有连接(join)),文档间的引用(“外键”)通常是在客户端通过向服务器进行额外查询来解决的(linking)。
这些连接总是在客户端解决的。直接/手动做这些是非常容易并且也是推荐这样做的。
这里还有一个很多驱动都支持的DBRef机制,它在一定程度上抽象了linking的概念。推荐的方法是使用直接/手动link。
内嵌对象是对linking的一种备选方案并且很多时候它非常合适和表现优秀。
简单的直接/手动linking
通常,手动编写link解决方案就可以很好工作并且也很简单。我们存储_id中的值到数据库的其他文档,稍后对它进行查询。例如:
> // grab a random blog post:
> p = db.postings.findOne();
{
"_id" : ObjectId("4b866f08234ae01d21d89604"),
"author" : "jim",
"title" : "Brewing Methods"
}
> // get more info on author of post p. this is the "linking" step.
> a = db.users.findOne( { _id : p.author } )
{ "_id" : "jim", "email" : "jim@gmail.com" }
> // inverse: given an author, find all blog posts for the author
> db.postings.find( {author : a._id } )
DBRef
DBRef是一种创建文档间引用的更加正式的规范。DBRefs(通常)除了对象id外还包含一个集合名称。大多数开发者只在文档中的集合可以改变为其他的时候才使用DBRef。如果你引用的集合总是相同的,那么上面描述的手动引用会更加高效。
DBRef是在同一个数据库中一个文档对另一个文档的引用。一个数据库引用是标准的内嵌(JSON/BSON)对象:我们定义的一种约定,不是一个特殊类型。通过使用标准方法来表现,驱动和数据框架可以添加助手方法按照标准方法来操作引用。
在某些驱动中DBRef有一个优点,允许可选的原子性的客户端解引用。在很多场景中,你可以只是把_id存储为引用,然后按照前面“简单手动引用”章节所说进行解引用。
DBRef引用值的语法是:
{ $ref : <collname>, $id : <idvalue>[, $db : <dbname>] }
<collname>是被引用的集合名(没有数据库名),<idvalue>是引用对象的字段_id的值。$db是可选的(目前大部分驱动还不支持)并且允许引用的文档是其他数据库的(由<dbname>指定)。
不同语言/驱动中的DBRef
C#
使用DBRef类。构造函数的参数是集合名和_id。然后你可以使用Database类中的FollowReference方法来获取引用文档。
C++
c++驱动尚没有提供方法来自动遍历DBRefs。当然你还是可以手动来完成的。
Java
java使用DBRef类支持DB引用。
Javascript(mongo shell)
例子:
> x = { name : 'Biology' }
{ "name" : "Biology" }
> db.courses.save(x)
> x
{ "name" : "Biology", "_id" : ObjectId("4b0552b0f0da7d1eb6f126a1") }
> stu = { name : 'Joe', classes : [ new DBRef('courses', x._id) ] }
// or we could write:
// stu = { name : 'Joe', classes : [ {$ref:'courses',$id:x._id} ] }
> db.students.save(stu)
> stu
{
"name" : "Joe",
"classes" : [
{
"$ref" : "courses",
"$id" : ObjectId("4b0552b0f0da7d1eb6f126a1")
}
],
"_id" : ObjectId("4b0552e4f0da7d1eb6f126a2")
}
> stu.classes[0]
{ "$ref" : "courses", "$id" : ObjectId("4b0552b0f0da7d1eb6f126a1") }
> stu.classes[0].fetch()
{ "_id" : ObjectId("4b0552b0f0da7d1eb6f126a1"), "name" : "Biology" }
>
Perl
perl驱动没有提供方法自动遍历DBRefs,但是有一个CPAN包:MongoDBx::AutoDeref.当然你还可以手动遍历他们。
PHP
除了在数据库层面(MongoDB::createDBRef和MongoDB::getDBRef)和集合层面(MongoCollection::createDBRef和MongoCollection::getDBRef)的创建和解引用方法外,PHP还提供了MongoDBRef类来支持DB引用。
Python
在python中使用bson.dbref.DBRef类来创建一个DB引用。你还可以使用Database实例中的dereference方法让解引用变得更加容易。
Ruby
Ruby也使用DBRef类和DB实例中的dereference方法来支持DB引用。例如:
@db = Connection.new.db("blog")
@user = @db["users"].save({:name => "Smith"})
@post = @db["posts"].save({:title => "Hello World", :user_id => @user.id})
@ref = DBRef.new("users", @post.user_id)
assert_equal @user, @db.dereference(@ref)