MongoDB 关系
表示多个文档之间的逻辑上的互相联系,通过嵌入和引用来建立联系。
MongoDB 中的关系可以是:
- 1:1(1 对 1)
- 1:N(1 对多)
- N:1(多对 1)
- N:N(多对多)
嵌入式关系
使用嵌入式方法,将一个或多个文档嵌入到一个或多个的文档中。
例:
{
"_id":ObjectId("52ffc33cd85242f436000001"),
"contact": "987654321",
"dob": "01-01-1991",
"name": "Tom Benzamin",
"address": [
{
"building": "22 A, Indiana Apt",
"pincode": 123456,
"city": "Los Angeles",
"state": "California"
},
{
"building": "170 A, Acropolis Apt",
"pincode": 456789,
"city": "Chicago",
"state": "Illinois"
}]
}
将多个地址文档保存在一个用户的文档中,即将数据保存在单一的文档中,这种做法可以比较容易的获取和维护数据。
对应查询方法:
db.users.findOne({"name":"Tom Benzamin"},{"address":1})
注:
存在缺点,如果用户和用户地址在不断增加,数据量不断变大,会影响读写性能。
引用式关系
设计数据库的常用方法,通过引用文档的 id 字段来建立关系。
例:
{
"_id":ObjectId("52ffc33cd85242f436000001"),
"contact": "987654321",
"dob": "01-01-1991",
"name": "Tom Benzamin",
"address_ids": [
ObjectId("52ffc4a5d85242602e000000"),
ObjectId("52ffc4a5d85242602e000001")
]
}
通过读取用户地址的对象 id(ObjectId)来获取用户的详细地址。
对应查询方法:
这种方法需要两次查询,第一次查询用户地址的对象 id(ObjectId),第二次通过查询的 id 获取用户的详细地址信息。
>var result = db.users.findOne({"name":"Tom Benzamin"},{"address_ids":1})
>var addresses = db.address.find({"_id":{"$in":result["address_ids"]}})
MongoDB 数据库引用
MongoDB 引用有两种:
- 手动引用(Manual References)
- DBRefs
DBRefs vs 手动引用
一个文档从多个集合引用文档,应该使用 DBRefs
使用 DBRefs
DBRefs格式
{ $ref : , $id : , $db : }
- $ref:集合名称
- $id:引用的 id
- $db:数据库名称,可选参数
例:
{
"_id":ObjectId("53402597d852426020000002"),
"address": {
"$ref": "address_home",
"$id": ObjectId("534009e4d852427820000002"),
"$db": "w3cschoolcc"},
"contact": "987654321",
"dob": "01-01-1991",
"name": "Tom Benzamin"
}
对应查询方法:
>var user = db.users.findOne({"name":"Tom Benzamin"})
>var dbRef = user.address
>db[dbRef.$ref].findOne({"_id":(dbRef.$id)})
MongoDB 覆盖索引查询
- 所有的查询字段是索引的一部分
- 所有的查询返回字段在同一索引中
由于所有出现在查询中的字段是索引的一部分,MongoDB 无需在整个数据文档中检索匹配查询条件和返回使用相同索引的查询结果。
因为索引存在与 RAM 中,从索引中获取数据比通过扫描文档读取数据快得多。
建立联合索引
db.users.ensureIndex({gender:1,user_name:1})
该索引会覆盖以下查询:
db.users.find({gender:"M"},{user_name:1,_id:0})
即对于上述查询,MongoDB 不会去数据库文件中查找。相反,它会从索引中提取数据,数据查询速度非常快。
该索引不会覆盖以下查询:
db.users.find({gender:"M"},{user_name:1})
由于索引中不包括 _id 字段,所以以上实例中没有排除 _id,查询就不会被覆盖。
不能使用覆盖索引查询的情况:
- 所有索引字段是一个数组
- 所有索引字段是一个子文档
参考文档一: MongoDB 文档
参考文档二: MongoDB W3C文档