mongodb 是介于关系型与非关系型数据之间的,mongodb的join查询可以通过引用来实现。

可以将文档内容嵌入到另一个文档中,也可以将文档内容引用到另一个文档中。

嵌入意味着要把某一类型的数据,如包含更多数据的数组,嵌入到文档本身。

引用意味着创建一个引用,包含另一个文档的数据。相当于关系型数据库。

一. 嵌入

例如:我想使用一个关系型数据库来记录CD、DVD和购买信息。在这个数据中,需要一个表来收集CD,另一个表来存储CD歌曲信息。因此,如果要查询特定的信息就可能需要查询多个表的。

对于mongodb 或者其他非关系型数据库,会更容易的嵌入这些信息,采用这种方法会使数据库简洁,确保所有相关信息保存在单一的文档中,同时,检索数据更快。

数据结构如下:

关系型

|_media
|_cds
|_id, artist, title, genre, releasedate
|_ cd_tracklists
|_cd_id, songtitle, length


|_media
|_cds
|_id,artist,title,genre,releasedate
|_cd_tracklists
|_cd_id,songtitle,length
非关系型
|_media
|_items


|_media
|_items
|_

对于非关系型,文档看起来如下所示

[
{
"_id" : ObjectId("5353463193efef02c962da73"),
"Type" : "CD",
"Artist" : "Nirvana",
"Title" : "Nevermind",
"Tracklist" : [
{
"Track" : "1",
"Title" : "Smells like teen spirit",
"Length" : "5:02"
},
{
"Track" : "2",
"Title" : "In Bloom",
"Length" : "4:15"
}
]
}
]


{
"_id":ObjectId("5353463193efef02c962da73"),
"Type":"CD",
"Artist":"Nirvana",
"Title":"Nevermind",
"Tracklist":[
{
"Track":"1",
"Title":"Smells like teen spirit",
"Length":"5:02"
},
{
"Track":"2",
"Title":"In Bloom",
"Length":"4:15"
}
]
}
]

上面这个例子中,歌曲信息嵌入到文档本身中,在关系型数据库中至少需要两个表,在非关系型数据库中,仅需要一个集合和一个文档。在检索信息时,只需要数据从一个文档加载到内存中,而不必加载多个文档。

二. 引用

在很多场景下,把数据嵌入到文档足以满足很多应用程序,如上所示。然而,有时就需要引用另一个文档。

在mongodb中的文档引用是通过执行额外的查询来解决的。

mongodb提供两种方式来实现:手动引用和使用DBRef标准。

2.1 手动引用

手动引用是最简单最直接的方式。当手动引用数据时,将其他文档的_id值存储在你的文档中。实例如下:

> use ttlsa_com
switched to db ttlsa_com
> apress = ( { "_id" : "Apress", "Type" : "Technical Publisher", "Category" : ["IT", "Software","Programming"] } )
{
"_id" : "Apress",
"Type" : "Technical Publisher",
"Category" : [
"IT",
"Software",
"Programming"
]
}
> db.publisherscollection.insert(apress)


>usettlsa_com
switchedtodbttlsa_com
>apress=({"_id":"Apress","Type":"Technical Publisher","Category":["IT","Software","Programming"]})
{
"_id":"Apress",
"Type":"Technical Publisher",
"Category":[
"IT",
"Software",
"Programming"
]
}
>db.publisherscollection.insert(apress)

引用

> book = ( { "Type" : "Book", "Title" : "Definitive Guide to MongoDB, the", "ISBN" : "987-1-4302-3051-9", "Publisher" : "Apress","Author" : ["Membrey,Peter","Plugge, Eelco","Hawkins, Tim"] } )
{
"Type" : "Book",
"Title" : "Definitive Guide to MongoDB, the",
"ISBN" : "987-1-4302-3051-9",
"Publisher" : "Apress",
"Author" : [
"Membrey,Peter",
"Plugge, Eelco",
"Hawkins, Tim"
]
}
> db.mediaCollection.insert(book)


>book=({"Type":"Book","Title":"Definitive Guide to MongoDB, the","ISBN":"987-1-4302-3051-9","Publisher":"Apress","Author":["Membrey,Peter","Plugge, Eelco","Hawkins, Tim"]})
{
"Type":"Book",
"Title":"Definitive Guide to MongoDB, the",
"ISBN":"987-1-4302-3051-9",
"Publisher":"Apress",
"Author":[
"Membrey,Peter",
"Plugge, Eelco",
"Hawkins, Tim"
]
}
>db.mediaCollection.insert(book)
检索
> book = db.mediaCollection.findOne({"ISBN" : "987-1-4302-3051-9"})
{
"Author" : [
"Hawkins, Tim",
"Plugge, Eelco"
],
"ISBN" : "987-1-4302-3051-9",
"Publisher" : "Apress",
"Title" : " Different Title 2",
"Type" : "Book",
"_id" : ObjectId("5353462f93efef02c962da71")
}
> book.Publisher
Apress
> db.publisherscollection.findOne( { _id : book.Publisher } )
{
"_id" : "Apress",
"Type" : "Technical Publisher",
"Category" : [
"IT",
"Software",
"Programming"
]
}


>book=db.mediaCollection.findOne({"ISBN":"987-1-4302-3051-9"})
{
"Author":[
"Hawkins, Tim",
"Plugge, Eelco"
],
"ISBN":"987-1-4302-3051-9",
"Publisher":"Apress",
"Title":" Different Title 2",
"Type":"Book",
"_id":ObjectId("5353462f93efef02c962da71")
}
>book.Publisher
Apress
>db.publisherscollection.findOne({_id:book.Publisher})
{
"_id":"Apress",
"Type":"Technical Publisher",
"Category":[
"IT",
"Software",
"Programming"
]
}

2.2 DBRef

DBRef提供了一个更正式的规范引用文档之间的数据。

在DBRef中,数据库引用以标准的JSON/ BSON嵌入对象存储的。

语法: { $ref : , $id : [, $db : ] }

代表引用的集合的名称。

所引用的文档的_id值。

$ db是可选的,引用的文档所在的数据库的名称。

> apress = ( { "Type" : "Technical Publisher", "Category" :["IT","Software","Programming"] } )
{
"Type" : "Technical Publisher",
"Category" : [
"IT",
"Software",
"Programming"
]
}
> db.publisherscollection.save(apress)
> apress
{
"Type" : "Technical Publisher",
"Category" : [
"IT",
"Software",
"Programming"
],
"_id" : ObjectId("53588c221697e7511678752c")
}
> book = { "Type" : "Book", "Title" : "Definitive Guide to MongoDB, the", "ISBN" : "987-1-4302-3051-9", "Author": ["Membrey, Peter","Plugge,Eelco","Hawkins, Tim"], Publisher : [ new DBRef ('publisherscollection',apress._id) ] }
{
"Type" : "Book",
"Title" : "Definitive Guide to MongoDB, the",
"ISBN" : "987-1-4302-3051-9",
"Author" : [
"Membrey, Peter",
"Plugge,Eelco",
"Hawkins, Tim"
],
"Publisher" : [
DBRef("publisherscollection", ObjectId("53588c221697e7511678752c"))
]
}
> db.media.save(book)
> db.media.find().toArray()
[
{
"_id" : ObjectId("53588ce01697e7511678752d"),
"Type" : "Book",
"Title" : "Definitive Guide to MongoDB, the",
"ISBN" : "987-1-4302-3051-9",
"Author" : [
"Membrey, Peter",
"Plugge,Eelco",
"Hawkins, Tim"
],
"Publisher" : [
DBRef("publisherscollection", ObjectId("53588c221697e7511678752c"))
]
}
]


>apress=({"Type":"Technical Publisher","Category":["IT","Software","Programming"]})
{
"Type":"Technical Publisher",
"Category":[
"IT",
"Software",
"Programming"
]
}
>db.publisherscollection.save(apress)
>apress
{
"Type":"Technical Publisher",
"Category":[
"IT",
"Software",
"Programming"
],
"_id":ObjectId("53588c221697e7511678752c")
}
>book={"Type":"Book","Title":"Definitive Guide to MongoDB, the","ISBN":"987-1-4302-3051-9","Author":["Membrey, Peter","Plugge,Eelco","Hawkins, Tim"],Publisher:[newDBRef('publisherscollection',apress._id)]}
{
"Type":"Book",
"Title":"Definitive Guide to MongoDB, the",
"ISBN":"987-1-4302-3051-9",
"Author":[
"Membrey, Peter",
"Plugge,Eelco",
"Hawkins, Tim"
],
"Publisher":[
DBRef("publisherscollection",ObjectId("53588c221697e7511678752c"))
]
}
>db.media.save(book)
>db.media.find().toArray()
[
{
"_id":ObjectId("53588ce01697e7511678752d"),
"Type":"Book",
"Title":"Definitive Guide to MongoDB, the",
"ISBN":"987-1-4302-3051-9",
"Author":[
"Membrey, Peter",
"Plugge,Eelco",
"Hawkins, Tim"
],
"Publisher":[
DBRef("publisherscollection",ObjectId("53588c221697e7511678752c"))
]
}
]

三. 比较

嵌入 :

小的子文档

数据不经常改变

当最终一致性是可以接受的

文档增长小

经常需要进行二次查询来获取数据

读快

引用 :

大的子文档

非易失性数据

当实时一致性是必要的

文档增长大

经常需要从结果中排除数据

写快