一、概述
有两种方法可以查询内嵌文档:查询整个文档;针对键值对进行查询。这两种方式是不同的,下面我通过例子进行分别说明。
二、查询整个文档
例如:有如下文档
class GoalReportMongoModel(Document):
id = StringField(primary_key=True)
user_id = StringField()
date = StringField()
update_time = LongField()
goals = ListField()
leader_id = StringField()
comment = StringField()
checked = BooleanField()
check_time = LongField()
参考示例:查询date 为2016-08-05 user_id 为U06UGFL12
可以这样查询
db.getCollection("goal_report").find({date:'2016-08-05',user_id:'U06UGFL12'})
这种查询会去精确匹配整个内嵌文档
三、键值对查询
我们一般在查询时,不会去匹配整个内嵌文档,通常只针对内嵌文档的特定键值去查询。怎么做?
答:查询文档时,可以使用"."来表示进入内嵌文档。
参考实例:
db.getCollection("goal_report").find({"goals.goal":'价值目标COO-1',"goals.assigner":'san.zhang'})
查询结果
{
"_id" : "U06UGFL12_2016-08-05",
"user_id" : "U06UGFL12",
"date" : "2016-08-05",
"update_time" : NumberLong(1470397732),
"goals" : [
{
"status" : "ensure",
"criterion_ok" : true,
"user_id" : "U06UGFL12",
"goal" : "价值目标COO-1",
"assigner" : "san.zhang",
"tool" : "",
"method_ok" : true,
"done_time" : NumberInt(0),
"method" : "",
"reason" : "本周",
"criterion" : "",
"goal_type" : "valuable",
"expire_time" : NumberInt(0),
"execution" : NumberInt(2),
"id" : NumberInt(1135241564),
"planh" : ""
},
{
"status" : "ensure",
"criterion_ok" : true,
"user_id" : "U06UGF232",
"goal" : "价值目标COO-2",
"assigner" : "san.zhang",
"tool" : "",
"method_ok" : true,
"done_time" : NumberInt(0),
"method" : "",
"reason" : "本周",
"criterion" : "",
"goal_type" : "valuable",
"expire_time" : NumberInt(0),
"execution" : NumberInt(2),
"id" : NumberInt(1135241564),
"planh" : ""
},
],
"leader_id" : "U08EC7FTM",
"checked" : true
}
四、数组里面包含内嵌文档的查询
这种查询相对来说比较复杂一点,所以内嵌文档的匹配也需要有些技巧。例如下面的博客文档中有一个commens:键用来保存别人的评论信息。
db.blog.insert({
"_id":"B001",
"title":"MongoDB查询",
"comments":[
{"name":"ickes","score":3,"comment":"nice"},
{"name":"xl","score":4,"comment":"nice"},
{"name":"eksliang","score":5,"comment":"nice"},
{"name":"ickes","score":6,"comment":"nice"}
]
})
现在要查询由ickes评论的且5分以上文章
- 不能使用db.blog.find({"comments":{"name":"ickes","score":{"$gt":5}})去查,因为内嵌文档的匹配是精确匹配,必须要匹配完整的文档,而这个查询不会匹配comment键
- 不能使用db.blog.find({"comments":{"name":"ickes","score":{ '$gt' : 5},"comment":"nice"}})去查,还是那句话,文档的匹配时精确匹配,这里使用了$gt作为范围,所以也查不到
- 不能使用db.blog.find({"comments.name":"ickes","comments.score":{"$gt":5}})去查,前面讲查询条件的时候说过,查询条件里面的键值对会解释为AND,但是对于数组的内嵌文档他会解释为OR的关系,也就是说上面实际是这样的comments.name:ickes或者comments.score":{"$gt":5},这明显不行吗!(注意如果内嵌文档不在数组中,还是AND,所以我才把这个拿出来单独讨论)
那对于数组里面的内嵌文档到底怎么办?应该这么办,如下所示
这里需要使用"$elemMatch"操作符,仅当这种时候才使用这个操作符
db.blog.find({"comments":{
"$elemMatch":{"name":"ickes","score":{"$gt":5}}
}})
五、返回与查询条件相匹配的任意一个数组元素
我们可以使用"$slice"操作符进行数组元素返回限制,但是当数组里面保存的是文档的时候,我就想返回与我查询条件相匹配的那个元素,其他的不要,怎么做?有技巧的哦!
文档结构如下:
db.blog.insert({
"_id":"B001",
"title":"MongoDB查询",
"comments":[
{"name":"ickes","score":3,"comment":"nice"},
{"name":"xl","score":4,"comment":"nice"},
{"name":"eksliang","score":5,"comment":"nice"},
{"name":"ickes","score":6,"comment":"nice"}
]
})
参考实例:
db.blog.find({"comments":{
"$elemMatch":{"name":"ickes","score":{"$gt":5}}}},
{"comments.$":1}--第二个参数是限制返回数据的,别看错了,这是第二个参数
)
返回结果如下:仅返回与当前查询条件相匹配的那个内嵌文档。
{
"_id" : "B001",
"comments" : [ { "name" : "ickes", "score" : 6, "comment" : "nice" } ]
}
如果当前查询有多个内嵌文档匹配,只会返回第一个
六、按照正则表达式查询内嵌文档某个字段包含某个字符串
举例:
{
"_id" : "U08G7H48Y_2016-07-08",
"user_id" : "U08G7H48Y",
"date" : "2016-07-08",
"update_time" : NumberLong(1467978750),
"goals" : [
{
"status" : "unsure",
"user_id" : "U08G7H48Y",
"goal" : "价值目标:确保IA项目组盈利指标达标",
"assigner" : "",
"tool" : "",
"method_ok" : true,
"id" : NumberInt(1363999581),
"done_time" : NumberInt(0),
"reason" : "短期目标不能确保:找不到更好的拿新用户的方法",
"create_time" : NumberLong(1466508766869),
"criterion" : "确保每天收入达到5w,力争6w\nFollow:1w\nLike:1.5w\nTracker:0.5w\nPrivacy:1.5w\nMemoryBoost:1.5w",
"expire_time" : NumberInt(0),
"execution" : NumberInt(2),
"method" : "已经入思维导图。\n确保7月30日收入达到1.5w",
"planh" : ""
},
{
"status" : "ensure",
"user_id" : "U08G7H48Y",
"goal" : "价值目标:确保给组员制造W-W局面",
"assigner" : "",
"tool" : "Wunderlist",
"method_ok" : true,
"id" : NumberLong(2633899071),
"done_time" : NumberInt(0),
"reason" : "",
"create_time" : NumberLong(1465283369329),
"criterion" : "帮助管理者(李丁,时迁,贾博,卢燕涛,孟友阳)盯住他的组员",
"expire_time" : NumberInt(0),
"execution" : NumberInt(1),
"method" : "确保增加项目负责人的管理组员能力:\n李丁每两周跟我Review一下他的组员:需要设置李丁的ToDo\n时迁每两周跟我Review一下他的组员:需要设置时迁的ToDo\n卢燕涛每两周跟我Review一下他的组员:需要设置卢燕涛的ToDo\n孟友阳每周跟我Review一下他的组员:需要设置孟友阳的ToDo\n\n确保跟每个PM每个季度至少聊天一次: 已设置Review聊天记录的todo",
"planh" : ""
},
{
"status" : "unsure",
"user_id" : "U08G7H48Y",
"goal" : "价值目标:确保PM可以流动起来",
"assigner" : "",
"tool" : "",
"method_ok" : true,
"id" : NumberInt(602193464),
"done_time" : NumberInt(0),
"reason" : "最近入职PM比较难,感觉流动这个目标会看不住",
"create_time" : NumberLong(1465284005711),
"criterion" : "确保组内PM新老搭配合理\n确保组内新PM快速培训",
"expire_time" : NumberInt(0),
"execution" : 1.5,
"method" : "确保7月底之前输入两个pm",
"planh" : ""
},
{
"status" : "ensure",
"user_id" : "U08G7H48Y",
"goal" : "价值目标:确保项目组流程完善",
"assigner" : "",
"tool" : "",
"method_ok" : true,
"id" : NumberInt(1616685108),
"done_time" : NumberInt(0),
"reason" : "",
"create_time" : NumberLong(1465284199829),
"criterion" : "确保项目组DEV流程完善",
"expire_time" : NumberInt(0),
"execution" : 1.5,
"method" : "确保项目组DEV流程完善",
"planh" : ""
},
{
"status" : "unsure",
"user_id" : "U08G7H48Y",
"goal" : "价值目标:确保项目组执行力达到1X",
"assigner" : "",
"tool" : "",
"method_ok" : false,
"id" : NumberLong(4283629091),
"done_time" : NumberInt(0),
"reason" : "暂时没有找到好的方法确保这个目标",
"create_time" : NumberLong(1465284143431),
"criterion" : "MB每周提交一个版本\nPM每周提交一个版本\niOS每两完成一个Feature",
"expire_time" : NumberInt(0),
"execution" : NumberInt(2),
"method" : "每个单子Archive的时候要想一些是否需要rethink",
"planh" : ""
},
{
"status" : "ensure",
"user_id" : "U08G7H48Y",
"goal" : "价值目标:确保盯住竞争对手的程序",
"assigner" : "",
"tool" : "Wunderlist",
"method_ok" : true,
"id" : NumberLong(3852562557),
"done_time" : NumberInt(0),
"reason" : "",
"create_time" : NumberLong(1465283982245),
"criterion" : "确保看榜单,Like,Tracker等竞品",
"expire_time" : NumberInt(0),
"execution" : 1.5,
"method" : "确保每",
"planh" : ""
},
{
"status" : "ensure",
"user_id" : "U08G7H48Y",
"goal" : "焦点目标",
"assigner" : "",
"tool" : "Wunderlist",
"method_ok" : true,
"id" : NumberInt(1973727620),
"done_time" : NumberInt(0),
"reason" : "",
"create_time" : NumberLong(1465284255588),
"criterion" : "确保关键字推广在持续推进",
"expire_time" : NumberInt(1469808000),
"execution" : 1.5,
"method" : "推广ROI",
"planh" : ""
},
{
"status" : "unsure",
"user_id" : "U08G7H48Y",
"goal" : "焦点目标:确保",
"assigner" : "",
"tool" : "",
"method_ok" : true,
"id" : NumberInt(123662851),
"done_time" : NumberInt(0),
"reason" : "这周上线的时候。",
"create_time" : NumberLong(1465278975537),
"criterion" : "交叉",
"expire_time" : NumberInt(1467216000),
"execution" : NumberInt(2),
"method" : "详见思维导图",
"planh" : ""
},
{
"status" : "ensure",
"user_id" : "U08G7H48Y",
"goal" : "焦点目标:确保跟进产品需求,多跟PM讨论各种产品需求",
"assigner" : "",
"tool" : "",
"method_ok" : true,
"id" : NumberLong(3918152115),
"done_time" : NumberInt(0),
"reason" : "",
"create_time" : NumberLong(1467335980569),
"criterion" : "确保每天至少找一个PM讨论需求15分钟\n确保每次产品需求评审会都参加",
"expire_time" : NumberInt(0),
"execution" : NumberInt(2),
"method" : "每天至少找一个PM讨论需求15分钟,已经入todo\n",
"planh" : ""
}
],
"leader_id" : "U06UGFL12",
"comment" : "个人产品能力和",
"check_time" : NumberLong(1468158420)
}
mongo 原生代码查询
db.getCollection("goal_report").find({"goals":{"$elemMatch":{"goal":{"$regex":/价值目标/}}}})
mongoengine 查询
GoalReportMongoModel.objects(__raw__={"goals":{"$elemMatch":{"goal":{"$regex":'价值目标'}}}})
七、 查询数组
数组元素模糊匹配
数组字段badges每个包含该元素black的文档都将被返回
db.users.find({badges:"black"},{"_id":1,badges:1})
# 结果
{ "_id" : 1, "badges" : [ "blue", "black" ] }
{ "_id" : 4, "badges" : [ "red", "black" ] }
{ "_id" : 6, "badges" : [ "black", "blue" ] }
数组元素精确(全)匹配
数组字段badges的值为["black","blue"]的文档才能被返回(数组元素值和元素顺序全匹配)
db.users.find({badges:["black","blue"]},{"_id":1,badges:1})
#结果
{ "_id" : 6, "badges" : [ "black", "blue" ] }
数组内嵌文档查询
查询数组points内嵌文档键points的值小于等于55的文档,此处通过.成员的方式实现
db.users.find( { 'points.points': { $lte: 55}},{"_id":1,points:1})
# 结果
{ "_id" : 3, "points" : [ { "points" : 81, "bonus" : 8 }, { "points" : 55, "bonus" : 20 } ] }
{ "_id" : 4, "points" : [ { "points" : 53, "bonus" : 15 }, { "points" : 51, "bonus" : 15 } ] }