MongoDB 学习笔记

感谢 Karl Seguin 编写的 The Little MongoDB Book 这本 MongoDB 入门书。javascript

本文内容主要来自「The Little MongoDB Book」的学习,学习笔记基于我的理解对原书部份内容进行调整。html

若是你是 MongoDB 数据库初学者,建议从学习「The Little MongoDB Book」 开始。java

若是须要练习 MongoDB 相关命令行工具可直接阅读本学习笔记。git

笔者测试 MongoDB 数据库版本较早,但文中涉及的全部 MongoDB 概念及命令行工具基本适用于全部版本。github

一 简介

了解 MongoDB 前先了解 NoSQL,NoSQL 是一种数据存储系统(非关系型数据库系统),相比 MySQL 这类关系型数据库提供通用的数据存储解决方案,NoSQL 倾向负责解决系统中一部分数据存储问题。算法

MongoDB 是一种 NoSQL 解决方案,提供更加通用的 NoSQL 方案。mongodb

本文约定 Mongo 和 MongoDB 都是代指 MongoDB 数据库系统。shell

二 准备

2.1 安装和运行 Mongo 服务

在学习 MongoDB 以前,须要安装 MongoDB 环境。可到 官方下载页面 下载须要的 MongoDB 版本。数据库

  1. Windows 操做系统能够在 这里 下载对应的 MongoDB 安装包。
  2. 解压下载的包(到任意路径)并进入 bin 子目录,暂且不要执行任何命令。让我先介绍一下,mongod 将启动服务器进程,而 mongo 会打开客户端的 shell,——大部分时间咱们将和这两个可执行文件打交道。
  3. bin 子目录中建立一个新的文本文件,取名为。
  4. mongodb.config 中加一行:
dbpath=PATH_TO_WHERE_YOU_WANT_TO_STORE_YOUR_DATABASE_FILES

例如,在 Windows 中您须要添加的多是 dbpath=c:\mongodb\data,而在Linux下可能就是 dbpath=/etc/mongodb/data。数组

  1. 确认您指定的dbpath是存在的。
  2. 执行 mongod,带上参数--config /path/to/your/mongodb.config。命令是这样的 mongod --config /path/to/your/mongodb.config

上面的安装步骤用于安装和启动 MongoDB 服务器进程。下面以 Windows 系统为例,讲解 MongoDB 安装及启动详细过程。

  1. 将安装包解压到 *c:mongodb*
  2. 建立 c:\mongodb\data\ 文件夹,该文件夹将用于存储 MongoDB 的数据;
  3. 建立 c:\mongodb\bin\mongodb.config 配置文件并添加 dbpath=c:\mongodb\data\ 配置;
  4. 命令行中进入 c:\mongodb\bin 目录,执行 c:\mongodb\bin\mongod --config c:\mongodb\bin\mongodb.config 启动 Mongo 服务;

对于不建立 c:\mongodb\bin\mongodb.config配置的用户,能够经过 --dbpath 参数启动服务,执行 c:\mongodb\bin\mongod --dbpath c:\mongodb\data\;效果和使用 --config 参数同样。

接下来,咱们经过 SHELL 环境链接 MongoDB 服务。进入 c:\mongodb\bin 目录,执行 mongo 命令,便可完成 MongoDB 服务链接。

须要说明的是 MongoDB 在 c:\mongodb\bin,提供了一些工具,其中就包括上去的 mongod.exemongo.exe,它们对应 mongodmongo 命令。

2.2 MongoDB 基本概念

若是有使用过关系型数据库(如 MySQL),那么对数据库、表、行、字段这些概念不会陌生,在 MongoDB 中也有相似的数据结构,不过在 Mongo 中将以另外一种形式存在:

  1. 数据库 (database)至关于 SQL 中的 database
  2. 集合 (collection)至关于 SQL 中的 table
  3. 文档 (document)至关于 SQL 中的 row
  4. 域 (field)至关于 SQL 中的 column
  5. 索引 (index)至关于 SQL 中的 index
  6. 主键 (primaryKey)至关于 SQL 中的主键,但 MongoDB 会自动在插入(insert)数据时将 _id 域,设置为主键字段

MongoDB 和 关系型数据库相关概念关系对照表:

SQL术语/概念 MongoDB术语/概念 解释/说明
database database 数据库
table collection 数据库表/集合
row document 数据记录行/文档
column field 数据字段/域
index index 索引
table joins 表链接,MongoDB不支持
primary key primary key 主键,MongoDB自动将_id字段设置为主键

表格信息引用自 MongoDB 概念解析

2.2.1 与数据库、集合、文档相关经常使用命令

下文中全部命令,需在命令终端执行。当使用 mongo 命令成功链接 MongoDB 服务后,可使用 help 获取 MongoDB 数据库使用帮助,它的执行结果大体以下:

> help
    db.help()                    help on db methods
    db.mycoll.help()             help on collection methods
    rs.help()                    help on replica set methods
    help admin                   administrative help
    help connect                 connecting to a db help
    help keys                    key shortcuts
    help misc                    misc things to know
    help mr                      mapreduce

    show dbs                     show database names
    show collections             show collections in current database
    show users                   show users in current database
    show profile                 show most recent system.profile entries with time >= 1ms
    show logs                    show the accessible logger names
    show log [name]              prints out the last segment of log in memory, 'global' is default
    use <db_name>                set current database
    db.foo.find()                list objects in collection foo
    db.foo.find( { a : 1 } )     list objects in foo where a == 1
    it                           result of the last line evaluated; use to further iterate
    DBQuery.shellBatchSize = x   set default number of items to display on shell
    exit                         quit the mongo shell

1 显示 MongoDB 数据库

执行 show dbs,显示 MongoDB 全部数据库

2 切换 MongoDB 数据库

执行 use test,将工做数据库切入到 test 数据库。在 MongoDB 中没有相似关系数据库的 Schema 概念,因此即便 MongoDB 的数据库未建立,也能够任意切换工做数据库。

3 显示数据库中的集合(collection)

执行 show colections,会打印输出当前数据库中的全部数据库集合。

4 获取工做数据库帮助信息

当使用 use test 进入 test 数据库后,能够执行 db.help() 指令查看 database 级别支持的命令,结果以下:

> db.help()
DB methods:
        db.addUser(username, password[, readOnly=false])
        db.auth(username, password)
        db.cloneDatabase(fromhost)
        db.commandHelp(name) returns the help for the command
        db.copyDatabase(fromdb, todb, fromhost)
        db.createCollection(name, { size : ..., capped : ..., max : ... } )
        db.currentOp() displays the current operation in the db
        db.dropDatabase()
        db.eval(func, args) run code server-side
        db.getCollection(cname) same as db['cname'] or db.cname
        db.getCollectionNames()
        db.getLastError() - just returns the err msg string
        db.getLastErrorObj() - return full status object
        db.getMongo() get the server connection object
        db.getMongo().setSlaveOk() allow this connection to read from the nonmaster member of a replica pair
        db.getName()
        db.getPrevError()
        db.getProfilingLevel() - deprecated
        db.getProfilingStatus() - returns if profiling is on and slow threshold
        db.getReplicationInfo()
        db.getSiblingDB(name) get the db at the same server as this one
        db.isMaster() check replica primary status
        db.killOp(opid) kills the current operation in the db
        db.listCommands() lists all the db commands
        db.logout()
        db.printCollectionStats()
        db.printReplicationInfo()
        db.printSlaveReplicationInfo()
        db.printShardingStatus()
        db.removeUser(username)
        db.repairDatabase()
        db.resetError()
        db.runCommand(cmdObj) run a database command.  if cmdObj is a string, turns it into { cmdObj : 1 }
        db.serverStatus()
        db.setProfilingLevel(level,<slowms>) 0=off 1=slow 2=all
        db.shutdownServer()
        db.stats()
        db.version() current version of the server
        db.getMongo().setSlaveOk() allow queries on a replication slave server
        db.fsyncLock() flush data to disk and lock server for backups
        db.fsyncUnock() unlocks server following a db.fsyncLock()

5 查看工做数据库名

须要查看当前工做的数据库,执行以下命令

> db.getName()
test1

6 查看工做数据库统计信息

db.stats() 会列出工做数据库中 集合、数据库大小等有用的信息。

> db.stats()
{
    "db":"test", --查看的是哪一个数据库
    "collections":7, --collection数量
    "objects":28, --对象数量
    "avgObjSize":50.57142857142857, --对象平均大小
    "dataSize":1416, --数据大小
    "storageSize":31744, --数据大小(含预分配空间)
    "numExtents":7, --事件数量
    "indexes":7, --索引数量
    "indexSize":57344, --索引大小
    "fileSize":50331648, --文件大小
    "ok":1 --本次取stats是否正常
}

上例结果引用自 db.stats() - 显示当前db状态

7 删除数据库

当须要删除 某个 数据库时,请先使用 use 指令切换工做数据库至待删除数据库。而后执行 db.dropDatabase() 指令。

> show dbs
    local   (empty)
    test    0.03125GB
    test1   (empty)

> use test1
    switched to db test1

> db.dropDatabase()
{ "dropped" : "test1", "ok" : 1 }

> show dbs
local   (empty)
test    0.03125GB

有了上面的基本概念,咱们就知道如何使用 MongoDB 的数据库和数据集了,下面是一个小练习,来加深相关知识的使用及理解:

2.2.2 MongoDB 训练场

场景:咱们开辟一个训练场,将完成数据库服务启动、客户端链接 MongoDB 服务、查看和选择数据库及数据库删除操做。

约定在 shell 中以 -- 开始的注释说明信息:执行时请不要赋值注释信息。

-- 1. 启动一个 Windows 命令行窗口,开启 MongoDB 服务

> cd c:\mongodb\bin
> mongod --config c:\mongodb\bin\mongodb.config

-- 2. 另启动一个 Windows 命令行窗口链接 MongoDB 服务
> cd c:\mongodb\bin
> mongo

MongoDB shell version: 2.0.7
connecting to: test

-- 3. 查看全部数据库
> show dbs

local   (empty)
test    0.03125GB
test1   (empty)

-- 4. 切换工做数据库至 blog
> use blog

switched to db blog

-- 5. 查看当前工做数据库

> db.getName()

blog

-- 6. 切换工做数据库至 test
> use test

switched to db test

-- 7. 查看当前工做数据库

> db.getName()

test

-- 8. 切回工做数据库至 blog
> use blog

switched to db blog

-- 9. 查看 blog 库的全部集合, 因为是空数据库因此会没有返回信息
> show collections

-- 10 查看 blog 库的状态,因为是空数据库因此统计信息内相关数据为空

> db.stats()
{
        "db" : "blog",
        "collections" : 0,
        "objects" : 0,
        "avgObjSize" : 0,
        "dataSize" : 0,
        "storageSize" : 0,
        "numExtents" : 0,
        "indexes" : 0,
        "indexSize" : 0,
        "fileSize" : 0,
        "nsSizeMB" : 0,
        "ok" : 1
}

-- 11. 插入一个用户到 blog 数据库的 user 集合里。
-- 不知道如何插入?不要紧,直接复制下面的命令就行了。
> db.user.insert({name: 'huliuqing', age: 18, hobby: ['coding', 'reading']})

-- 12. 查看刚刚 user 集合的插入结果
> db.user.find()
{ "_id" : ObjectId("5abde35e7d318c10d73539e3"), "name" : "huliuqing", "age" : 18, "hobby" : [ "coding", "reading" ] }

-- 13. 再看下 blog 库的状态
> db.stats()
{
        "db" : "blog",
        "collections" : 3,
        "objects" : 5,
        "avgObjSize" : 51.2,
        "dataSize" : 256,
        "storageSize" : 16384,
        "numExtents" : 3,
        "indexes" : 1,
        "indexSize" : 8176,
        "fileSize" : 16777216,
        "nsSizeMB" : 16,
        "ok" : 1
}

-- 14. 删除 user 集合
-- 不知道使用什么命令?那先来查看下 user 集合层级的帮助信息吧
> db.user.help()
...
    db.user.drop() drop the collection
...

> db.user.drop()
true

-- 14. 再看下 blog 库的状态
{
        "db" : "blog",
        "collections" : 2,
        "objects" : 1,
        "avgObjSize" : 36,
        "dataSize" : 36,
        "storageSize" : 8192,
        "numExtents" : 2,
        "indexes" : 0,
        "indexSize" : 0,
        "fileSize" : 16777216,
        "nsSizeMB" : 16,
        "ok" : 1
}

-- 15. 删除 blog 数据库
> db.dropDatabases()
{ "dropped" : "blog", "ok" : 1 }

-- 16. 再看下 blog 库的状态
> db.stats()
{
        "db" : "blog",
        "collections" : 0,
        "objects" : 0,
        "avgObjSize" : 0,
        "dataSize" : 0,
        "storageSize" : 0,
        "numExtents" : 0,
        "indexes" : 0,
        "indexSize" : 0,
        "fileSize" : 0,
        "nsSizeMB" : 0,
        "ok" : 1
}

-- 17 查看下数据库
> show dbs

local   (empty)
test    0.03125GB
test1   (empty)

2.3 MongoDB 基本概念总结

  1. MongoDB 有 数据库 组成;数据库由 集合 组成;集合由 文档组成;文档包含一个或多个 ;且集合能够被 索引,以提高 查找排序 效率。
  2. 在关系型数据库中在数据表(table)层级定义列(column)信息;在 NoSQL 中是在 文档 这一层定义 ,即一个集合里的每一个文档均可以有本身的域。
  3. MongoDB 中的集合是无模式的(schema-less),无需提早建立(即不须要像 SQL 同样 CREATE TABLE 或 CREATE DATABASE)。
  4. 命令的分类
  • 全局命令,使用 help 查看全局命令
  • 当前数据库级别命令,执行 db.help() 命令查看
  • 当前集合级别命令,执行 db.your_collection.help() 命令查看。

另外须要说明的是 MongoDB 的 SHELL 运行于 JavaScript 之上。除全局命令外,操做 db 数据库、 db.COLLECTION_NAME 操做集合,若缺乏 () 将会在 SHELL 里打印出方法的实现源码。

三 MongoDB CRUD 操做

前面咱们学习了如何使用 MongoDB 的帮助,接下来在学习 CRUD 操做以前,进一步了解下 MongoDB 的数据库及集合是如何建立的。

MongoDB 是 无模式 的,当使用 use YOUR_DATABASE 命令切换数据库时,咱们无需预先建立 YOUR_DATABASE 数据库,而当向某个 集合 插入一个 文档 时,将会自动生成具体的数据库、集合和文档。

如:

> use mongo_playground
> db.users.insert({name: 'huliuqing', age: 18, gender: 'male'})

上面的命令对 users 集合作 insert(插入文档) 操做,传入的参数是一个 JSON 格式数据。经过 show collections 命令查看到有: userssystem.indexes 两个集合存在,其中 system.indexes 集合会在每一个 数据库MongoDB 自主建立,这个集合包含数据库中的索引信息。

在执行 insert 命令时,MongoDB 会生成一个值为 ObjectId 类型的 _id 域_id 域 对每一个 文档 都是必须的,它相似于 SQL 的主键,咱们可使用本身的算法生成 _id 的值,大部分状况下使用 MongoDB 的默认值就能够了。

前面说过 _id 域 相似主键,它的索引信息被存储在 system.indexes 集合内,咱们看看两个集合里有什么数据:

-- 1. 查看集合
> show collections

system.indexes
users

-- 2. 查看 users 集合数据
> db.users.find().pretty()
{
        "_id" : ObjectId("5ac2f7ecfdcd54e4d368bde5"),
        "name" : "huliuqing",
        "age" : 18,
        "gender" : "male"
}

-- 3. 查看 system.indexes 集合数据
> db.system.indexes.find().pretty()
{
        "v" : 1,
        "key" : {
                "_id" : 1
        },
        "ns" : "mongo_playground.users",
        "name" : "_id_"
}

从结果咱们能够看到 users 集合比添加的 JSON 多了 _id 域,它的索引信息被 system.indexes 集合记录。

3.1 CRUD - CREATE 建立 MongoDB 数据

建立一个 文档db.YOUR_COLLECTION.insert() 命令完成,咱们向 db.users 集合插入一条新的文档:

-- 1. 建立文档
> db.users.insert({name: 'zhangsanfeng', age: 120, gender: 'male', hobby: ['Kung fu', 'Tai Chi']});

-- 2. 查询结果
> db.users.find()
{ "_id" : ObjectId("5ac2f7ecfdcd54e4d368bde5"), "name" : "huliuqing", "age" : 18, "gender" : "male" }
{ "_id" : ObjectId("5ac3165bfdcd54e4d368bde6"), "name" : "zhangsanfeng", "age" : 120, "gender" : "male", "hobby" : [ "Kung fu", "Tai Chi" ] }

3.2 CRUD - RETRIEVE 查询 MongoDB 数据

一个简单的查询操做可使用 db.YOUR_COLLECTION.find() 指令来获取全部 YOUR_COLLECTION 集合的全部文档列表。除此以外,咱们还须要知道在 MongoDB 中有个 查询构造器 的概念,查询构造器 相似于 SQL 中的 WHERE 语句

查询构造器

在学习查询构造器以前,咱们先清洗下 mongo_playground 数据库,并加入测试集合。

-- 1. 进入 mongo_playground 数据库
> use mongo_playground

-- 2. 删除 mongo_playground 数据库
> db.dropDatabase()

-- 3. 建立测试数据
db.users.insert({name: 'Bob',birthday: new Date(1992,2,13,7,47),hobby: ['basketball','football'],weight: 60,gender: 'm',age: 18});
db.users.insert({name: 'John',birthday: new Date(1991, 0, 24, 13, 0),hobby: ['basketball', 'ping pong'],weight: 45,gender: 'm',age: 23});
db.users.insert({name: 'Tony',birthday: new Date(1973, 1, 9, 22, 10),hobby: ['boxing', 'racing'],weight: 98,gender: 'm',age: 30});
db.users.insert({name: 'Lily',birthday: new Date(1997, 6, 1, 10, 42),hobby: ['ping pong', 'yoga'],weight: 69,gender: 'f',age: 39});
db.users.insert({name: 'Jack',birthday: new Date(1979, 7, 18, 18, 44),hobby: ['skiing'],weight: 57,gender: 'm',age: 51});
db.users.insert({name: 'Tom',birthday: new Date(1985, 6, 4, 2, 1),hobby:['skiing', 'basketball','boxing'],weight:65,gender:'m',age:29});
db.users.insert({name: 'Jackson',birthday: new Date(1998, 2, 7, 8, 30),hobby: ['skateboard', 'running'],weight: 73,gender: 'f',age: 41});
db.users.insert({name: 'Lucy',birthday: new Date(2005, 4, 3, 0, 57),hobby: ['skiing', 'yoga'],weight: 42,gender: 'f',age: 22});
db.users.insert({name: 'Peter',birthday: new Date(2001, 9, 8, 14, 53),hobby: ['shooting', 'darts'],weight: 60,gender: 'm',age: 48});
db.users.insert({name: 'Rose',birthday: new Date(1997, 2, 1, 5, 3),hobby: ['shooting', 'darts'],weight: 65,gender: 'f',age: 56});
db.users.insert({name: 'Lee',birthday: new Date(1999, 11, 20, 16, 15),hobby: ['ping pong', 'basketball'],weight: 54,gender: 'm'});

3.2.1 条件查询

3.2.1.1 基础条件查询 {fieldName: value}

查找用户 name 等于 Lee 的信息

> db.users.find({name: 'Lee'}).pretty()
{
        "_id" : ObjectId("5ac31e00fdcd54e4d368bdfc"),
        "name" : "Lee",
        "birthday" : ISODate("1999-12-20T08:15:00Z"),
        "hobby" : [
                "ping pong",
                "basketball"
        ],
        "weight" : 54,
        "gender" : "m"
}

3.2.1.2 查询 {fieldName1:value1, fieldName2:value2}

查找喜欢 跑步男性

> db.users.find({gender: 'm', hobby: 'racing'}).pretty()
{
        "_id" : ObjectId("5ac31e00fdcd54e4d368bdf4"),
        "name" : "Tony",
        "birthday" : ISODate("1973-02-09T14:10:00Z"),
        "hobby" : [
                "boxing",
                "racing"
        ],
        "weight" : 98,
        "gender" : "m",
        "age" : 30
}

3.2.1.3 查询 {$or: [{fieldName: value1}, {fieldName: value2}]}

查找喜欢 乒乓球瑜伽男性

-- 1. 仅查找喜欢 乒乓球 或 瑜伽 的用户
> db.users.find({gender: 'm', $or: [{hobby: 'ping pong'}, {hobby: 'yoga'}]})

{ "_id" : ObjectId("5ac327edfdcd54e4d368be09"), "name" : "John", "birthday" : ISODate("1991-01-24T05:00:00Z"), "hobby" : [ "basketball", "ping pong" ], "weight" : 45, "gender" : "m", "age" : 23 }
{ "_id" : ObjectId("5ac327edfdcd54e4d368be12"), "name" : "Lee", "birthday" : ISODate("1999-12-20T08:15:00Z"), "hobby" : [ "ping pong", "basketball" ], "weight" : 54, "gender" : "m" }

-- 2. 下面的查找将查找到全部的喜欢 乒乓球 或 瑜伽 的用户
> db.users.find({$or: [{hobby: 'ping pong'}, {hobby: 'yoga'}]})

3.2.1.4 比较查询

经过 $lt(less than: 小于)**、**$lte(less than and equal: 小于等于)$gt(greater than: 大于)**、**$gte(greater than and equal: 大于等于)$ne(not equal: 不等于) 等实现比较查询。

-- 1. 查询年龄大于等于 30 岁且小于  40 岁的用户
> db.users.find({age: {$gte: 30, $lt: 40}})

-- 2. 查询年龄大于 55 岁的用户
> db.users.find({age: {$gt: 55}})

-- 3. 查询年龄小于 18 岁的用户
> db.users.find({age: {$lt: 20}})

-- 4. 查询年龄不等于 18 岁的用户
> db.users.find({age: {$ne: 18}})

3.2.1.5 判断文档中是否存在某个域

3.2.1.4 的第 4 个示例 4. 查询年龄不等于 18 岁的用户 会查询到没有 age 域的用户 Lee。经过 $exists 指令能够判断某个域是否存在,它的值是 bool 类型,咱们对这个示例作些改进:

-- 1. 查询年龄字段存在且年龄不等于 18 岁的用户
> db.users.find({age: {$ne: 18, $exists: true}})

3.2 总结

本章了解了 MongoDB 相关查询操做,了解更多查询命令细节能够查看 查询文档。但更重要的是反复练习这些查询语句的基本用法。

3.3 CRUD - UPDATE 更新 MongoDB 数据

MongoDB 的更新须要特别关注一下,更新数据使用 db.YOUR_COLLECTIONS.update(query, object, options) 方法,update 接收两个必选参数:查询选择器须要更新的域

3.3.1 UPDATE 覆盖 与 UPDATE $set 更新

一个简单的示例,咱们找到 年龄 48 岁 的用户 Peter,将他的年龄 更新为 49 岁

> db.users.find({age: 48}).pretty()
{
        "_id" : ObjectId("5ac42ff514c16270040db426"),
        "name" : "Peter",
        "birthday" : ISODate("2001-10-08T06:53:00Z"),
        "hobby" : [
                "shooting",
                "darts"
        ],
        "weight" : 60,
        "gender" : "m",
        "age" : 48
}

> db.users.update({age: 48}, {age: 49})

> db.users.find({age: 49}).pretty()
{ "_id" : ObjectId("5ac42ff514c16270040db426"), "age" : 49 }

再次查找 年龄 49 岁 的用户,会发现 更新后 Perter 用户数据被 覆盖{ "_id" : ObjectId("5ac42ff514c16270040db426"), "age" : 49 }(由于 ObjectId 相同)。

这是由于: 在 MongoDB 中接收的第二个参数,若是没有使用 $set 修饰符,将会采起 覆盖 文档操做,而不是 更新文档指定域,这和 SQL 的 UPDATE 语句行为不同。

正确的更新 应该是下面的 update 写法使用 {$set: {age: 49}},操做以前咱们要清空并重建测试数据。

> db.users.find({age: 48}).pretty()
{
        "_id" : ObjectId("5ac42ff514c16270040db426"),
        "name" : "Peter",
        "birthday" : ISODate("2001-10-08T06:53:00Z"),
        "hobby" : [
                "shooting",
                "darts"
        ],
        "weight" : 60,
        "gender" : "m",
        "age" : 48
}

> db.users.update({age: 48}, {$set: {age: 49}})

> db.users.find({age: 49}).pretty()
{
        "_id" : ObjectId("5ac4375b14c16270040db43c"),
        "name" : "Peter",
        "birthday" : ISODate("2001-10-08T06:53:00Z"),
        "hobby" : [
                "shooting",
                "darts"
        ],
        "weight" : 60,
        "gender" : "m",
        "age" : 49
}

建议: 在执行 删除更新 这类操做前,建议先采用相同的查询条件查找数据,结果与判断一致时再作 删除更新 等操做。

3.3.2 UPDATE $inc 和 $push 修饰符

  • $inc 修饰符,对文档中的某个域增长一个 正值负值
  • $push 修饰符,向域的值为数组中添加新值。
-- 1. Peter 又长大了一岁
> db.users.find({name: 'Peter'})
{ "_id" : ObjectId("5ac4375b14c16270040db43c"), "name" : "Peter", "birthday" : ISODate("2001-10-08T06:53:00Z"), "hobby" : [ "shooting", "darts" ], "weight" : 60, "gender" : "m", "age" : 49 }
> db.users.update({name: 'Peter'}, {$inc: {age: 1}})

-- 2. Peter 越活越年轻
> db.users.find({name: 'Peter'})
{ "_id" : ObjectId("5ac4375b14c16270040db43c"), "name" : "Peter", "birthday" : ISODate("2001-10-08T06:53:00Z"), "hobby" : [ "shooting", "darts" ], "weight" : 60, "gender" : "m", "age" : 50 }

> db.users.update({name: 'Peter'}, {$inc: {age: -5}})

-- 3. 由于 Peter 有了更多的兴趣爱好
> db.users.update({name: 'Peter'}, {$push: {hobby: 'racing'}})
{ "_id" : ObjectId("5ac4375b14c16270040db43c"), "age" : 45, "birthday" : ISODate("2001-10-08T06:53:00Z"), "gender" : "m", "hobby" : [ "shooting", "darts", "racing" ], "name" : "Peter", "weight" : 60 }

3.3.3 UPDATE upsert 选项: 插入新文档或更新文档域数据

MongoDB update 方法第三个参数接收 bool 值的标识符,该值默认为 false。当该值设为 true 时若 查询选择器 的目标文档存在,则采起 update $set 域 操做;若不存在则采起 INSERT 操做。

这个选项在相似 网站点击计数器 统计场景中很是有用。若是网页点击记录存在则更新记录数,不存在则执行插入操做。

-- 1. 给 users 页面统计点击数, update 第三个参数为 false 或 缺省,将不会建立 hits 集合
> db.hits.update({page: 'users'}, {$inc: {hits: 1}})
> db.hits.find()

-- 2. upsert 选项设置为 true,在执行 update 更新操做时,hits 集合未建立,执行建立操做
> db.hits.update({page: 'users'}, {$inc: {hits: 1}}, {upsert: true})
> db.hits.find()
{ "_id" : ObjectId("5ac4427bb5b4350bc6d2f715"), "hits" : 1, "page" : "users" }

-- 3. upsert 选项设置为 true,在执行 update 更新操做时,hits 集合已建立,执行更新操做
> db.hits.update({page: 'users'}, {$inc: {hits: 1}}, {upsert: true})
> db.hits.find()
{ "_id" : ObjectId("5ac4427bb5b4350bc6d2f715"), "hits" : 2, "page" : "users" }

3.3.4 批量更新

MongoDB update 操做在 3.3.1 介绍过,更新数据须要 $set 修饰符,不然执行覆盖操做。这里咱们介绍它的第二个独特特性:默认更新一条记录

当咱们须要给全部用户加上点赞数 likes 域用于记录用户获得的赞,咱们会想下面的方法同样执行,但仅仅只有一条文档加上了 likes 域:

> db.users.update({}, {$set:{likes: 0}})
> db.users.find({likes: 0})

multi 选项值设为 true 能够实现全部文档记录新增 操做。

> db.users.update({}, {$set:{likes: 0}}, false, true)
> db.users.find({likes: 0})

能够在文档查看 update 方法相关具体使用。

3.4 CRUD - DELETE 删除 MongoDB 数据

经过 db.YOUR_COLLECTION.remove(query, justOne) 能够删除一个或全部 文档,参数接收的查询选择器为空时删除全部文档,当 justOne 标识为 true 是仅删除一条匹配文档。

-- 1. 删除用户 Bob 的记录
> db.users.find({name: 'Bob'})
> db.users.remove({name: 'Bob'})
> db.users.find({name: 'Bob'})

-- 2. 删除全部用户
> db.users.find()
> db.users.remove()
> db.users.find()

相关细节能够查阅 删除文档

若是须要删除全部文档,咱们还能够经过 db.YOUR_COLLECTIONS.drop() 方法实现,drop() 方法不只删除全部文档还会删除该集合的索引信息。

3.5 CRUD - 重识 RETRIEVE 查询 MongoDB 数据

咱们在 3.2 章节中了解了有关 MongoDB 的查询功能。本节咱们将学习包括查询指定域、排序、返回的结果集记录数限制和分页等功能,这些方法在应用程序开发过程当中会十分常见。

3.5.1 返回指定域

在 Mongo Shell 里咱们经过 db.YOUR_COLLECTION.find 注意 无 () 能够看到 find 方法的具体实现,find 一共能够接收 4 个参数:第一个参数是查询选择器;第二个参数即为指定返回的域。

以前,咱们都是返会全部的域信息,如今让咱们仅返回用户的用户名、年龄和性别:

> db.users.find({}, {name: true, age: true, gender: true})
{ "_id" : ObjectId("5acada245c193d1acc967575"), "name" : "Bob", "gender" : "m", "age" : 18 }
{ "_id" : ObjectId("5acada245c193d1acc967576"), "name" : "John", "gender" : "m", "age" : 23 }
{ "_id" : ObjectId("5acada245c193d1acc967577"), "name" : "Tony", "gender" : "m", "age" : 30 }
...

默认 _id 域总会做为查询结果返回,能够设置 {_id: falsee} 显示的排除掉。

3.5.2 排序

在 MongoDB 中咱们还须要了解一个基本概念 游标(cursor),因为前面咱们并无涉及到游标的使用(只是看起来没有涉及到游标)。

find 方法返回的结果即为依据查询选择器匹配到的文档集合的 游标,这样能够经过链式操做对 find 结果集进行处理。

咱们在 MongoDB Shell 里输入 db.users.help() 命令能够看到下面的帮助信息:

> db.users.help()
...
        db.users.find([query],[fields]) - query is an optional query filter. fields is optional set of fields to return.
                                                      e.g. db.users.find( {x:77} , {name:1, x:1} )
        db.users.find(...).count()
        db.users.find(...).limit(n)
        db.users.find(...).skip(n)
        db.users.find(...).sort(...)
...

countlimitskipsort 等方法便是做用在 find 返回的游标上。

下面咱们依据用户的年龄按照 升序降序 排列:

-- 1. 依据升序排列
> db.users.find({}, {name: 1, age: 1}).sort({age: 1})

-- 2. 依据降序排列
> db.users.find({}, {name: 1, age: 1}).sort({age: -1})

3.5.3 分页

要实现分页功能须要结合使用 skip(n)limit(n) 两个方法,它们的返回值也是一个游标。skip 会选择游标的起始位置,limit 相似 SQL 的 limit 语句表示返回的结果集最大纪录条数。

下面咱们查下年龄第二和第三大的用户:

-- 1. 先看下年龄最大的 5 名用户
> db.users.find({}, {name: true, age: 1}).sort({age: -1}).limit(5)

-- 2. 再看下年龄第二和第三大的用户
> db.users.find({}, {name: true, age: 1}).sort({age: -1}).skip(1).limit(2)

3.5.4 查询集合记录数

在 MongoDB 中能够直接使用 db.YOUR_COLLECTION.count() 方法获取集合记录数,也能够经过 db.YOUR_COLLECTION.find().count() 获取:

获取年龄大于等于 20 岁的用户数:

> db.users.count({age: {$gte: 20}})
> db.users.find({age: {$gte: 20}}).count()

可是要知道 db.YOUR_COLLECTION.count() 仅仅是 db.YOUR_COLLECTION.find().count() 的别名,在它的内部仍是调用 db.YOUR_COLLECTION.find().count()

> db.users.count
function (x) {
    return this.find(x).count();
}

更多有关做用于游标的方法能够查阅 游标方法

TO BE CONTINUE

相关文章
相关标签/搜索