MongoDB查询(3)——内嵌文档查询(七)

MongoDB查询内嵌文档

一、概述

       有两种方法可以查询内嵌文档:查询整个文档;针对键值对进行查询。这两种方式是不同的,下面我通过例子进行分别说明。

二、查询整个文档

例如:有如下文档

db.emp.insert({
	"id":"A001",
	"name":{
		"first":"Carey",
		"last":"Ickes"
	},
	"age":25
})

 参考实例:查询name等于"Carey Ickes"的人可以这样查询

db.emp.find({"name":{"first":"Carey","last":"Ickes"}})
        这种查询会去精确匹配整个内嵌文档,如果Carey决定添加一个中间名的键,那么这个查询就用不了,因为查询条件不在与整个内嵌文档相匹配。而且这种查询还与顺序有关,如果查询条件换成{"last":"Ickes","first":"Carey"},也会什么也匹配不到。

三、键值对查询

我们一般在查询时,不会去匹配整个内嵌文档,通常只针对内嵌文档的特定键值去查询。怎么做?

答:查询文档时,可以使用"."来表示进入内嵌文档。

参考实例:

> db.emp.find({"name.last":"Ickes","name.first":"Carey"})
现在,如Ickes增加了更多的键,这个查询依然会匹配他的姓跟名

 四、数组里面包含内嵌文档的查询

这种查询相对来说比较复杂一点,所以内嵌文档的匹配也需要有些技巧。例如下面的博客文档中有一个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分以上文章
  1. 不能使用db.blog.find({"comments":{"name":"ickes","score":{"$gt":5}})去查,因为内嵌文档的匹配是精确匹配,必须要匹配完整的文档,而这个查询不会匹配comment键
  2. 不能使用db.blog.find({"comments":{"name":"ickes","score":{"$gt":5},"comment":"nice"}})去查,还是那句话,文档的匹配时精确匹配,这里使用了$gt作为范围,所以也查不到
  3. 不能使用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" } ] 
}

 如果当前查询有多个内嵌文档匹配,只会返回第一个。