做为非关系型数据库中的佼佼者,MongoDB一大优点在于可以在一条文档中存储对象类型的数据,适当增长冗余来让数据库更好用。文档中一个对象类型的字段在MongoDB中被称为内嵌文档(Embedded),也是MongoDB推荐的存储形式。本文将基于官方文档介绍内嵌文档的查询方法。python
对于初创企业的技术团队来讲,快速变更的需求致使没有必要花费过多精力设计关系严格的数据表,而是能够直接将相关联的数据字段放在一块儿,好比如下设计:web
db.books.insertMany( [
{ _id: 1, name: "python", price: 25, size: { h: 14, w: 21}, reading: ["Tom","John"] },
{ _id: 2, name: "mongo", price: 50, size: { h: 8.5, w: 11}, reading: ["John","Dave"] },
{ _id: 3, name: "webGL", price: 80, size: { h: 8.5, w: 11}, reading: ["Lily"] },
]);
复制代码
若是使用相似关系型数据主键的将_id做为引用的方式以下:数据库
db.books.insertMany( [
{ _id: 1, name: "python", price: 25, h: 14, w: 21, reading: ["Tom","John"] },
{ _id: 2, name: "mongo", price: 50, h: 8.5, w: 11, reading: ["John","Dave"] },
{ _id: 3, name: "webGL", price: 80, h: 8.5, w: 11, reading: ["Lily"] },
]);
db.reading.insertMany( [
{ _id: 4, reader: "Tom", book_id:1 },
{ _id: 5, reader: "John", book_id:1 },
{ _id: 6, reader: "John", book_id:2 },
{ _id: 7, reader: "Dave", book_id:2 },
{ _id: 8, reader: "Lily", book_id:3 },
]);
复制代码
相比之下,内嵌的方式有如下优势:bash
内嵌文档能够下降字段修改对调用者的影响,好比在size字段下增长一个名为"l"的子字段表示书籍长度,对于调用者来讲只须要在用到时从size对象中拿出来便可,不须要再去额外获取新的字段。 所以,在内嵌文档较小,更新频率不高时推荐使用内嵌文档来存储数据。spa
以1中数据为例,对于单值的字段查询,只须要写一个查询字典(query filter)便可:设计
db.books.find( { price: 25 } );
复制代码
当查询条件涉及内嵌文档中的子字段时,使用"."(可递进使用):code
db.books.find( { "size.h": 8.5 } );//针对字典对象
-->[
{ _id: 2, name: "mongo", price: 50, size: { h: 8.5, w: 11}, reading: ["John","Dave"] },
{ _id: 3, name: "webGL", price: 80, size: { h: 8.5, w: 11}, reading: ["Lily"] },
]
db.books.find( { "reading.0": "Tom" } );//针对列表
-->[
{ _id: 1, name: "python", price: 25, h: 14, w: 21, reading: ["Tom","John"] },
]
复制代码
注意,不使用"."的话将会严格匹配内嵌文档:对象
db.books.find( { "size": { h: 8.5} } );//不存在size字段为{ h: 8.5}的文档
-->[]
复制代码
同普通查询同样,可使用运算符Query Operator:文档
db.books.find( { "size.w": { $lt: 21} } );
-->[
{ _id: 2, name: "mongo", price: 50, size: { h: 8.5, w: 11}, reading: ["John","Dave"] },
{ _id: 3, name: "webGL", price: 80, size: { h: 8.5, w: 11}, reading: ["Lily"] },
]
复制代码
示例数据string
db.books.insertMany( [
{ _id: 1, name: "python", price: 25, size: [14,21], reading: ["Tom","John"] },
{ _id: 2, name: "mongo", price: 50, size: [8.5,11], reading: ["John","Dave"] },
{ _id: 3, name: "webGL", price: 80, size: [8.5,11], reading: ["Lily"] },
]);
复制代码
以1中数据为例,指定列表,将严格按照全部元素及其顺序查询:
db.books.find( { reading: ["Tom","John"]" }); -->[ { _id: 1, name: "python", price: 25, size: size: [14,21], reading: ["Tom","John"] }, ] 复制代码
若只要求指定元素存在且不要求顺序,使用$all:
db.books.find( { reading: { $all: ["John"] } });
-->[
{ _id: 1, name: "python", price: 25, size:[14,21], reading: ["Tom","John"] },
{ _id: 2, name: "mongo", price: 50, size:[8.5,11], reading: ["John","Dave"] },
]
复制代码
db.books.find( { reading: "John" });//只要列表中有一元素的值为"John"即知足
-->[
{ _id: 1, name: "python", price: 25, size:[14,21], reading: ["Tom","John"] },
{ _id: 2, name: "mongo", price: 50, size:[8.5,11], reading: ["John","Dave"] },
]
db.books.find( { size: { $gt: 16, $lt: 15} });//只要列表中有一元素的值大于16,还有一元素小于15即知足
-->[
{ _id: 1, name: "python", price: 25, size: [14,21], reading: ["Tom","John"] },
]
复制代码
使用$elemMatch
db.books.find( { size: { $elemMatch: { $gt: 22, $lt: 30 } } });
-->[
{ _id: 1, name: "python", price: 25, size: [14,21], reading: ["Tom","John"] },
]
复制代码
使用$size
db.books.find( { reading: { $size: { $gt: 1} } });
-->[
{ _id: 3, name: "webGL", price: 80, size: [8.5,11], reading: ["Lily"] },
]
复制代码
总结,对于列表类型的内嵌文档,$elemMatch给出的并列条件要求至少有一个元素同时知足,不使用elemMatch时并列的条件只须要各自至少有一个元素知足便可。