`
mj4d
  • 浏览: 302961 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

mongodb: find

阅读更多

有段时间没看书了,记录下这个周末看《MongoDB权威指南》的笔记,目前看到是第四章:查询

find({查询条件限定},{返回字段})

这是一个查询的基本语法,各个签名的作用已经说得很清楚。下面来细细展开:

当然最开始插入一批数据以供测试:

db.users.insert({"_id": 1, "name": "aroba", "age": 22, "friends": 3})
db.users.insert({"_id": 2, "name": "brob", "age": 23, "friends": 4})
db.users.insert({"_id": 3, "name": "robin", "age": 24, "friends": 23})
db.users.insert({"_id": 4, "name": "ccrob", "age": 25, "friends": 32})
db.users.insert({"_id": 5, "name": "drobin", "age": 26, "friends": 15})
db.users.insert({"_id": 6, "name": "rrobin", "age": "az", "friends": 19})
 

1、 方法中的第一个参数:查询条件限定是一个document结构,如为{}将默认返回所有数据

#查询一个年龄为27的用户:
db.users.find({"age":23})
#查询一个年龄为27,姓名为robin的用户,相当于AND
db.users.find({"age":23, "name":"brob"})

作为文档的查询条件,可以支持更复杂的格式:

#查询年龄大于20且小于30的用户
db.users.find({"age":{"$gt":20, "$lte":23}})

这里条件查询有常用的:小于("$lt")、小于等于("$lte")、大于("$gt")、大于等于("$gte")、不等于("$ne") 。这些条件查询对数字日期类型的字段比较适用

 

前面说到同时查询age和name属性,相当于AND查询。这里来看看OR查询,主要通过"$in"和"$or" 。对单一键有多个值与其匹配的话就用"$in",后面跟一个条件数组。

#查询年龄在某个范围的用户:
db.users.find({"age":{"$in":[20, 22, 25]}})

"$in" 对支持的类型非常灵活,不同类型的条件可以同时查询。与之相对应的就是"$nin",表示不在该范围内的键

db.users.find({"age":{"$in":[20, 22, 25, "az"]}})
db.users.find({"age":{"$nin":[20, 22, 25, "az"]}})

 与单一键的"$in"不同的是,"$or"是包含多个可能条件的数组。

#年龄在某个范围内或者name在某个范围内的用户
db.users.find({"$or": [{"age": 23 }, {"name": "robin"}]})
db.users.find({"$or": [{"age": {"$in": [ 23, 4, "az" ]} }, {"name": "robin"}]})

 

2、返回字段

作为查询的第二个参数,如果没有的话是默认返回所有字段。可以对需要的返回字段指定:

db.users.find({}, {"name":1, "age":1})

1、这个查询会返回name、age、_id字段
2、_id是默认返回,如果不要显示加上("_id":0)     

db.users.find({}, {"name":1, "age":1, "_id":0})

3、如果某个字段如age不存在,也不抛异常
4、需要显示的字段设置为大于零的数就可以,但还是用1好理解,但如果对不需要显示的字段且不是_id设置为0或其他会抛异常

db.users.find({}, {"name":1, "age":0, "_id":0})

 这样是不行的,如果不要返回age不加上就可以了

后面还将对数组查询的返回字段做相应的说明,这里就先到此

 

3、几点说明

1、"$not"元条件句,用在其他任何条件上,如

#age>20即查询age小于等于20的用户
db.user.find({"age": {"$not" : {"$gt" :20}}})  
#这里查询age不是1,6,11,16...等的用户
db.user.find({"age": {"$not": {"$mod": [5, 1]}}}) 

 

2、条件查询与更新修改器

#更新修改器
db.users.update({"age": 23},{"$set":{"name":"zzzz"}})
#条件查询
db.users.find({"age": {"$gt": 20}}) 

条件句是内层文档键,修改器是外层文档键。而且对同一个字段age来说可以是多个限定条件,但是修改器不能对应多个

 

3、null
如果某个字段的值为null,根据null来查询时可以返回该条文档,但也会返回不包含该字段的文档

#新增两条数据
>db.users.insert{ "_id" : 7, "age" : 23, "name" : "joe" }
>db.users.insert{ "_id" : 8, "age" : 24, "friends" : null, "name" : "sam" }

 查询键值为null的字段

>db.users.find({"friends": null})。

 这里会返回friends为null的文档,但是也会返回没有该键的文档

 

{ "_id" : 7, "age" : 23, "name" : "joe" }
{ "_id" : 8, "age" : 24, "friends" : null, "name" : "sam" }

 需要通过"$exists"来判定键值是否存在

> db.users.find({"friends":{"$in":[null],"$exists":true}})
{ "_id" : 8, "age" : 24, "friends" : null, "name" : "rrbin" }
 

4、正则表达式

#这里会返回所有name中包含rob字段的文档
> db.users.find({"name":/rob/})
#不仅对字段值进行正则匹配,如果值本身是正则式也匹配
 

 

4、数组查询

插入几条数据测试

db.food.insert({"_id": 1, "fruit": ["apple", "banana", "peach"]})
db.food.insert({"_id": 2, "fruit": ["apple", "orange"]})
db.food.insert({"_id": 3, "fruit": ["banana", "peach", "orange"]})

以下是一些常用的查询方法,直接上

#匹配fruit中包含banana的文档
db.food.find({"fruit": "banana"})
#必须匹配所有
db.food.find({"fruit": {"$all" : ["apple", "peach"]}})
#精确匹配
db.food.find({"fruit": ["apple", "orange"]})
#指定下标 key.index
db.food.find({"fruit.2": "peach"})
#查询指定长度的数组
db.food.find({"fruit": {"$size" : 3}})

但是"$size"操作只能严格匹配,遇到比如要求数组大于或者小于之类的查询就无能为力了。这里提供了解决的方案:对文档新增size字段,每次对数组push或pop操作时,对size字段做相应的增减。查询的时候再对字段size做相应的处理

db.food.update({"$push" :{"fruit" : "strawberry"} , "$inc" : {"size" : 1}})
db.food.find({"size" : {"$gt" : 3}})

 

返回数组指定子集
"$slice"用于返回数组的一个子集,支持前、后或者偏移

db.food.insert({"_id": 4, "fruit": ["apple", "banana", "peach", "orange", "watermelon", "lemon", "cherry"]})
#取前2个
db.food.find({"_id":4}, {"fruit":{"$slice":2}})
#{u'_id': 4, u'fruit': [u'apple', u'banana']}
#取后两个
db.food.find({"_id":4}, {"fruit":{"$slice":-2}})
#{u'_id': 4, u'fruit': [u'lemon', u'cherry']}
#从第2个开始取三个,这个其实达到分页的效果,但书中明确指出对大量数据skip性能下降厉害,不建议考虑这种方式
db.food.find({"_id":4}, {"fruit":{"$slice":[2, 3]}})
#{u'_id': 4, u'fruit': [u'peach', u'orange', u'watermelon']}

 使用"$slice"获取数组内的值时,其他的键也会默认返回,如果不需要返回非数组内的其他键这里可以指明,与前面返回不同的是这里可以用0

db.food.insert({"_id": 5, "sum":7, "fruit": ["apple", "banana", "peach", "orange", "watermelon", "lemon"]})
db.food.find({"_id":5}, {"fruit":{"$slice":[2, 3]}, "_id":0, "sum":0})
{u'fruit': [u'peach', u'orange', u'watermelon']}

 

5、查询内嵌文档

这里主要考虑匹配查询内嵌文档,考虑如下文档

db.users.insert({"_id": 9, "age":23, "name": {"first":"joe", "last":"sam"}})
db.users.insert({"_id": 10, "age":24, "name": {"first":"joe", "middle":"dd", "last":"sam"}})

查询名字为joe sam的用户

#查询名字为joe sam的用户
data = db.users.find({"name":{"first":"joe", "last":"sam"}})
#返回第一条,实际上这相当于精确匹配,这个查询条件将严格匹配顺序、字段的数量。其实第二条也是我们想要的结果,那么正确的写法应该是:
data = db.users.find({"name.first":"joe", "name.last":"sam"})

 书中说到一种复杂情况下的查询:joe发表的5分以上的评论:

db.blog.insert({"_id":1, "content":"....", "comments":[{"name":"joe", "score":3, "comment":"nice"}, {"name":"sam", "score":5, "comment":"zzz"}, {"name":"joe", "score":5, "comment":"good"}]})
data = db.blog.find({"comments":{"name":"joe", "score":{"$gte":5}}})
#这样是查不到数据的,内嵌文档要求匹配整个文档,而不是comments键
data = db.blog.find({"comments.name":"joe", "comments.score":{"$gte":5}})
#这个查询会返回这条记录,其实是匹配的commets中各个键,即joe匹配第一条,score匹配第二条
data = db.blog.find({"comments":{"$elemMatch":{"name":"joe", "score":{"$gte":5}}}})

 

 

6、分页

分页在前面说到"$slice"时,其实是达到分页的效果,前面也说了弊端,这里进一步说明。这里采用limit限制返回结果,slice跳过指定数量文档,sort对查询结果排序

limit
db.users.find().limit(3)结果集超过三条返回三条,不足返回实际数量,貌似对负数不感冒,比如-2还是返回前两条,或者limit里没有偏移这个概念
skip
db.users.find().limit(3)省略结果集前三个,返回剩下的,结果集不足三个就啥都木有了,当然这个也一样,别写负数了,否则抛异常
sort
对结果集排序:1升序,-1降序。可支持多个键/对

db.users.find().sort([("name", 1), ("age", -1)])
db.users.find().sort({"name":1,"age":-1})
#这就是分页
db.users.find().limit(2).sort("_id", 1)
db.users.find().limit(2).skip(2).sort("_id", 1)
db.users.find().limit(2).skip(4).sort("_id", 1)

这对大数据量的skip性能影响较大,这里也提供了一些绕过的方法。比如先取得最后一条的记录的某个唯一键,再查询大于该键的值。可以看出这个限制条件挺多,当然容易想到的采用主键"_id",这是主键必须是数字了

 

 

书中还说到了其他的一些高级特性,如$where、随机获取、包装查询、获取一致性结果等,这里就没记录下来

分享到:
评论

相关推荐

    Windows上安装MongoDB:完整步骤详解.pdf

    4. 查询数据:使用`db.<collection_name>.find()`命令,如`db.testcollection.find()`,查询集合中的所有数据。 通过以上步骤,你已经在Windows上成功安装并配置了MongoDB,可以开始进行数据库操作。对于初学者和有...

    fivem-mongodb:用于FiveM的MongoDB包装器

    FiveM MongoDB包装器 描述 该资源是用于的简单MongoDB包装。 它运行在之上。 安装 将此存储resources/mongodb到resources/mongodb文件夹。 将mongodb/database.... mongodb : findOne ({ collection = " users " , q

    fdb-document-layer:在FoundationDB上的文档数据模型,实现了MongoDB:registered:有线协议

    如果对文档层使用它,则在find命令上将失败。 这应该用修复。 由于文档层建立在FoundationDB之上,因此它继承了FoundationDB的强大保证。 因果一致性和强一致性是默认的操作模式。 索引始终与插入内容一致。 不...

    MySQL vs MongoDB

    - MongoDB:使用MQL(MongoDB查询语言),虽然也支持部分SQL语法,但更偏向于JSON风格的查询,如使用`find()`和`aggregate()`函数。 3. 性能与扩展性: - MySQL:通过主从复制、分区(Sharding)等方式实现水平...

    PHP实现的MongoDB数据库操作类分享

    这些操作通常会涉及MongoDB的`insert()`, `find()`, `update()`, `remove()`等方法。 总的来说,`HMongodb`类提供了一种封装好的方式来管理和操作MongoDB数据库,使得在PHP中进行MongoDB数据库交互变得更加便捷和...

    mongodb-erlang:Erlang的MongoDB驱动程序

    [{Result}] = mongodb:find_one(Pid, "users", Query). % 更新文档 Update = #{$set">> => #{<<"age">> => 31}}, {ok, _} = mongodb:update(Pid, "users", Query, Update). % 删除文档 {ok, _} = mongodb:remove...

    mongoDB:MongoDB备忘单

    例如,`db.collection.find()`用于获取集合中的所有文档,`db.collection.findOne()`则返回第一个匹配的文档。 4. **索引**: 为了提高查询性能,可以为字段创建索引。`db.collection.createIndex({field: 1})`会...

    springboot-mongodb:springboot-mongodb

    《SpringBoot与MongoDB深度整合指南》 在现代软件开发中,SpringBoot以其简洁的配置、快速的开发体验以及强大的生态系统,成为了Java开发者首选的框架之一。而MongoDB作为NoSQL数据库的代表,以其非关系型、分布式...

    Mongodb基本操作

    3. 查看用户:使用以下命令查看用户:`db.system.users.find()`。 4. 删除用户:使用以下命令删除用户:`db.system.users.remove({user:"bzm"})`。 四、数据库管理 1. 删除数据库:使用以下命令删除数据库:`db....

    API.NET-MongoDB:MongoDB集成的uma API.NET

    var values = await collection.Find(_ => true).ToListAsync(); return Ok(values); } // POST api/values [HttpPost] public IHttpActionResult Post([FromBody] dynamic value) { var collection = _...

    MongoDB:一些MongoDB测试

    db.myCollection.find({name: "John"}); ``` 更新文档: ```javascript db.myCollection.update({name: "John"}, {$set: {age: 31}}); ``` 删除文档: ```javascript db.myCollection.remove({name: "John"}); `...

    nodejs-mongodb:mongodb的nodejs操作

    MongoDB则是一种流行的开源、无模式的分布式文档数据库,常用于处理大量数据。当结合使用Node.js和MongoDB时,可以构建高性能、可扩展的数据驱动的Web应用。本篇文章将深入探讨如何在Node.js环境中操作MongoDB。 ...

    MongoDB:这是mongoDB示例

    MongoDB是一种流行的开源、分布式文档数据库系统,设计用于处理海量数据并提供高可用性和高性能。在本文中,我们将深入探讨MongoDB的核心概念、优势、与Java的集成以及如何使用Java进行MongoDB操作。 MongoDB的核心...

    mongodb:使用Java的Mongodb

    MongoDB是一种流行的开源、分布式文档型数据库,设计用于处理大量数据并提供高可用性和可扩展性。在Java应用程序中使用MongoDB,可以利用其灵活性和高性能特性,为现代Web应用和大数据处理提供强大的数据存储解决...

    MongoDB的安装(详细教程)

    查询数据用`db.collection.find()`。 ### 6. MongoDB安全管理 MongoDB支持用户认证和角色管理,以保护数据库安全。你可以通过`db.createUser()`创建用户,并指定相应的角色(如读写权限)。配置文件中的`security`...

    mongodb:nodejs共享

    MongoDB是一种流行的开源、分布式文档型数据库,设计用于处理大量数据并提供高可用性和高性能。在Web开发领域,特别是Node.js应用中,MongoDB经常被用作后端数据存储。Node.js是JavaScript的一个运行环境,它允许...

    Python-Flask-MongoDB:python-flask+mongodb实现的简单的restful api

    在本项目"Python-Flask-MongoDB"中,我们将探讨如何使用Python的Flask框架与MongoDB数据库来构建一个RESTful API。RESTful API是一种遵循REST(Representational State Transfer)架构约束的Web服务设计风格,它使得...

    MongoDB:MongoDB 教程

    db.collection.findOne({name: "John"}); db.collection.updateOne({name: "John"}, {$set: {age: 31}}); db.collection.deleteOne({name: "John"}); ``` 三、示意图 在 MongoDB 中,图形表示数据关系可以使用图形...

Global site tag (gtag.js) - Google Analytics