前面两篇中我们讨论了mongodb在java和php中的实战开发:JavaWeb和mongodb增删改查,php mongodb数据库开发。这篇文章开始讨论mongodb中的数据库关系和引用的原理和使用,关系也就是1对多或多对1这样的关系,关系可以通过嵌入和引用的方法建模,这种关系可以是:1:1一对一、1:N一对多、N:1多对一的关系或N:N多对多的关系。
让我们考虑为用户存储地址的情况,一个用户可以有多个地址,这是一个1:n的关系,如下是用户user的文档结构:
{
"_id":ObjectId("uu"),
"name": "Ao",
"contact": "369",
}
如下是用户的地址address的文档结构:
{
"_id":ObjectId("aa"),
"building": "22 A, Fool Apt",
"city": "LosC",
"state": "China"
}
1、建立嵌入式关系
在嵌入式方法中,我们将地址文档嵌入到用户文档中。
{
"_id":ObjectId("ee"),
"name": "EW",
"contact": "123",
"address": [
{
"_id":ObjectId("bb"),
"building": "30B",
"city": "Pin",
"state": "China"
},
{
"_id":ObjectId("cc"),
"building": "2 St",
"city": "xIN",
"state": "China"
}
]
}
这种方法在单个文档中维护所有相关数据,这使得检索和维护变得很容易。可以在单个查询中检索整个文档,比如:
db.users.findOne({"name": "EE"},{"address": 1})
使用嵌入式的缺点是,如果嵌入式文档的大小持续增长,就会影响读写性能。
2、使用手动引用构建关系
这就是设计归一化关系的方法,用户文档和地址文档将分别维护,用户文档将包含一个引用地址文档id字段的字段,如下:
{
"_id":ObjectId("ee"),
"name": "EW",
"contact": "123",
"address_ids": [
"_id":ObjectId("bb"),
"_id":ObjectId("cc"),
}
]
}
在上面的用户文档中包含数组字段address_ids,其中包含相应地址的对象。我们需要两个查询:首先从用户文档获取address_ids字段,然后从地址集合获取这些地址信息。
>var result = db.users.findOne({"name": "EE"}, {"address_ids": 1})
>var addresses = db.address.find({"_id": {"$in": result["address_ids"]}})
3、mongodb数据库引用
上面关于MongoDB关系的建模使用了引用关系的概念,也称为手动引用,在其中我们手动地将引用文档的id存储在其他文档中。但是,在文档包含来自不同集合的引用的情况下,我们可以使用MongoDB数据库引用。
(1)数据库引用手动引用的对比
作为一个示例场景,我们将使用数据库引用而不是手动引用,考虑这样一个数据库:我们将不同类型的地址(家里的、办公地点、邮件地址等)存储在不同的集合中。文档引用地址时它还需要根据地址类型指定查看哪个集合。在文档引用来自许多集合的文档的情况下,我们应该使用数据库引用。
(2)使用数据库引用
数据库应用有三个属性:
a、$ref –表示引用目标文档的所在集合名称
b、$id——对应所引用文档的_id
c、$db——这是一个可选字段,包含引用文档所在的数据库的名称
考虑一个具有数据库引用字段地址的示例用户文档,如代码片段所示
"_id":ObjectId("cc"),
"contact": "369",
"name": "PE",
"address": {
"$ref": "address_home",
"$id": ObjectId("gg"),
"$db": "website"
}
这里的address 数据库引用字段指定引用的地址文档位于website数据库下的address_home集合中,其id为gg。
下面的代码动态地在$ref参数指定的集合(在本例中为address_home)中查找一个id由数据库应用中的$id参数指定的文档。
>var user = db.users.findOne({"name": "CC"})
>var dbRef = user.address
>db[dbRef.$ref].findOne({"_id": (dbRef.$id)})
评论前必须登录!
注册