MongoDB查询内嵌文档

有两种方式可以查询内嵌文档

  • 查询整个文档

  • 针对键值对进行查询

查询整个文档

  db.emp.insert({
    "id":"A001",
    "name":{
        "first":"Carey",
        "last":"Ickes"
    },
    "age":25
  })
  db.emp.find({"name" : { "first" : "Carey", "last" : "Ickes" }})
> db.emp.find()
{ "_id" : ObjectId("561720d7de256e5153080ea7"), "id" : "A001", "name" : { "first" : "Carey", "last" : "Ickes" }, "age" : 25 }
> bb = db.emp.findOne({ "_id" : ObjectId("561720d7de256e5153080ea7") })
{
    "_id" : ObjectId("561720d7de256e5153080ea7"),
    "id" : "A001",
    "name" : {
        "first" : "Carey",
        "last" : "Ickes"
    },
    "age" : 25
}
> db.emp.find({"name" : { "first" : "Carey", "last" : "Ickes" }})
{ "_id" : ObjectId("561720d7de256e5153080ea7"), "id" : "A001", "name" : { "first" : "Carey", "last" : "Ickes" }, "age" : 25 }
> bb.name = { "first" : "Carey", "last" : "Ickes", "middle" : "Joe" }
{ "first" : "Carey", "last" : "Ickes", "middle" : "Joe" }
> db.emp.save(bb)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.emp.find({"name" : { "first" : "Carey", "last" : "Ickes" }})

这种查询会去精确匹配整个内嵌文档。如果其中name元素的子集发生变化,查询条件不与整个内嵌文档相匹配。
而且这种查询,还与顺序有关系。

键值对查询

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

> db.emp.find({ "name.last" : "Ickes", "name.first" : "Carey" })
{ "_id" : ObjectId("561720d7de256e5153080ea7"), "id" : "A001", "name" : { "first" : "Carey", "last" : "Ickes", "middle" : "Joe" }, "age" : 25 }

现在,如果Ickes增加了更多的键,这个查询依然会匹配他的姓跟名。

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


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.insert({
    "_id":"B002",
    "title":"MySQL查询",
    "comments":[
      {
        "name":"MySQL-ickes",
        "score":4,
        "comment":"nice"
      },
      {
        "name":"MySQL-xl",
        "score":9,
        "comment":"nice"
      },
      {
        "name":"MySQL-eksliang",
        "score":5,
        "comment":"nice"
      },
      {
        "name":"MySQL-ickes",
        "score":6,
        "comment":"nice"
       }
    ]
})

# 以下两种查询都是精确匹配文档,所以查询不出结果
> db.blog.find({ "comments" : { "name": "ickes", "score" : { "$gt" : 5 } } })
> db.blog.find({ "comments" : { "name": "ickes", "score" : { "$gt" : 5 }, "comment":"nice" } })

#
查询条件里面的键值对会解释为AND,但是对于数组的内嵌文档来说它会解释为OR的关系。也就是
说上面的解释会拆解为  comments.name : ickes 或者 comments.score : { "$gt" : 5 }
> db.blog.find({ "comments.name" : "ickes", "comments.score" : { "$gt":5 } })
{ "_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" } ] }

查询 "name" : "ickes", "score" : { "$gt" : 5 }

> db.blog.find({"comments" : { "$elemMatch" : { "name" : "ickes", "score" : { "$gt" : 5 } } }})
{ "_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" } ] }

查询 "score" : { "$gt" : 5 }

> db.blog.find({"comments" : { "$elemMatch" : { "score" : { "$gt" : 5 } } }})
{ "_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" } ] }
{ "_id" : "B002", "title" : "MySQL查询", "comments" : [ { "name" : "MySQL-ickes", "score" : 4, "comment" : "nice" }, { "name" : "MySQL-xl", "score" : 9, "comment" : "nice" }, { "name" : "MySQL-eksliang", "score" : 5, "comment" : "nice" }, { "name" : "MySQL-ickes", "score" : 6, "comment" : "nice" } ] }

返回与查询条件相匹配的任意一个数组元素

> db.blog.find({
    "comments" : {
      "$elemMatch" : {
        "name" : "ickes",
        "score" : { "$gt" : 5 }
      }
    }
},
{
  "comments.$" : 2
}
)

> { "_id" : "B001", "comments" : [ { "name" : "ickes", "score" : 6, "comment" : "nice" } ] }
> qq = db.blog.findOne({ "_id" : "B002" })

> qq.comments = [
        {
            "name" : "ickes",
            "score" : 9,
            "comment" : "nice"
        },
        {
            "name" : "MySQL-xl",
            "score" : 9,
            "comment" : "nice"
        },
        {
            "name" : "MySQL-eksliang",
            "score" : 5,
            "comment" : "nice"
        },
        {
            "name" : "MySQL-ickes",
            "score" : 6,
            "comment" : "nice"
        }
    ]

> db.blog.save(qq)


再次执行

db.blog.find({
    "comments" : {
      "$elemMatch" : {
        "name" : "ickes",
        "score" : { "$gt" : 5 }
      }
    }
},
{
  "comments.$" : 2
}
)

> db.blog.find({ "comments" : { "$elemMatch" : { "name" : "ickes", "score" : { "$gt" : 5 } } } }, { "comments.$" : 2 })
{ "_id" : "B001", "comments" : [ { "name" : "ickes", "score" : 6, "comment" : "nice" } ] }
{ "_id" : "B002", "comments" : [ { "name" : "ickes", "score" : 9, "comment" : "nice" } ] }
>

最后再执行

db.blog.find({
    "comments" : {
      "$elemMatch" : {
        "name" : "ickes",
        "score" : { "$gt" : 5 }
      }
    }
},
{
  "comments.$" : 1
}
)

{ "_id" : "B001", "comments" : [ { "name" : "ickes", "score" : 6, "comment" : "nice" } ] }
{ "_id" : "B002", "comments" : [ { "name" : "ickes", "score" : 9, "comment" : "nice" } ] }

注意只有一个查询条件,就可以不使用$elemMatch
下面两个查询是等价的

db.blog.find({ "comments.score" : { "$gt" : 5 } })
db.blog.find({ "comments" : { "$elemMatch" : { "score" : { "$gt" : 6 } } } })

$elemMatch 的用法

  • 元素匹配
db.nums.insert([{ "results" : [ 82, 85, 88 ] },{ "results" : [ 75, 88, 89 ] }])

查询 80 <= x < 85 的数据,数组中的任何一个元素都要
大于等于80并且小于等于85

> db.nums.find({ "results" : { "$elemMatch" : { "$gte" : 80, "$lt" : 85 } } })

{ "_id" : ObjectId("5617320ade256e5153080ea9"), "results" : [ 82, 85, 88 ] }

  • 数组内嵌文档
db.survey.insert([
{ _id: 1, results: [ { product: "abc", score: 10 }, { product: "xyz", score: 5 } ] },
{ _id: 2, results: [ { product: "abc", score: 8 }, { product: "xyz", score: 7 } ] },
{ _id: 3, results: [ { product: "abc", score: 7 }, { product: "xyz", score: 8 } ] }
{ _id: 4, results: [ { product: "abc", score: 10 }, { product: "xyz", score: 5 } ] },
{ _id: 5, results: [ { product: "abc", score: 8 }, { product: "xyz", score: 7 } ] },
{ _id: 6, results: [ { product: "abc", score: 7 }, { product: "xyz", score: 8 } ] }
])

查询 product 为 xyz,并且score 大于 8 的集合

> db.survey.find({ results: { $elemMatch: { product: "xyz", score: { $gte: 8 } } } })
{ "_id" : 3, "results" : [ { "product" : "abc", "score" : 7 }, { "product" : "xyz", "score" : 8 } ] }
{ "_id" : 6, "results" : [ { "product" : "abc", "score" : 7 }, { "product" : "xyz", "score" : 8 } ] }
>   db.survey.find({ results: { $elemMatch: { product: "xyz", score: { $gte: 8 } } } }, { "results.$" : 1 })
{ "_id" : 3, "results" : [ { "product" : "xyz", "score" : 8 } ] }
{ "_id" : 6, "results" : [ { "product" : "xyz", "score" : 8 } ] }

  • 单一查询条件

如果只有单一的查询条件,那么可以不用 $elemMatch

db.survey.find({
  results: { $elemMatch: { product: "xyz" } }
})

等同于

db.survey.find(
  { "results.product": "xyz" }
)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容

  • 目录 查询操作 集合查询方法 find() 查询内嵌文档 查询操作符(内含 数组查询) "$gt" 、"$gte"...
    彩虹之梦阅读 1,004评论 0 1
  • 查询数组很容易,对于数组,我们可以这样理解:数组中每一个元素都是这个键值对键的一个有效值,如下面的例子:我们要查询...
    yzc123446阅读 501评论 0 1
  • 一 基本概念 MongoDB中数据的结构为:库、集合、文档 1 数据库 多个集合可以组成数据库。MongoDb的单...
    周东波_db阅读 2,355评论 0 4
  • MongoDB 这几天编写程序,发现如果没有理论的支持,即使时间花的再多,效率也是不高的,所以每天在编程之前都应该...
    ofelia_why阅读 542评论 0 2
  • 主要是说明mongodb的数据查询方法,本次不使用mongo shell来操作,使用图形化操作软件Robo来执行m...
    Spareribs阅读 3,991评论 1 10