MongoDB 相关概念

MongoDB 中基本的概念是文档、集合、数据库。

数据库

MongoDB 的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中。

文档

文档类似于 MySQL 中的一条记录(row),其大小不能超过 16M。文档内的属性不能包含 null 字符,句点(.),美元符号($),不能以 system 开头。

文档的存储是以 JSON 的形式保存,在 MongoDB 中以 BSON(二进制的 JSON)的形式存储着。

{"site":"www.bestguo.top", "name":"BestGuo 的小窝"}

集合

集合中保存着一组文档,类似于 MySQL 中的表。集合存在于数据库中,没有固定的表结构。存储的方式可以如下。

{"site":"www.bestguo.top", "name":"BestGuo 的小窝"}
{"site":"www.bestguo.top", "name":"BestGuo 的小窝", "create": "2019-01-01" }
{"site":"www.bestguo.top", "name":"BestGuo 的小窝", "views": "6672", "clients": "2835"}

SQL 与 NoSQL 对比

SQL 与 NoSQL 的概念对比如下,这样就更好的理解 MongoDB 了。

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

MongoDB 数据库操作

show 命令

使用 show 命令查看全部的数据库

show databases
show dbs
# ============= Run Results ============= #
admin   0.000GB
config  0.000GB
local   0.000GB
test    0.001GB

使用 show 命令显示集合

show collections
# ============= Run Results ============= #
a
item
mythings
students
user

use 命令

使用 use 命令切换数据库

use admin # 切换至 admin 数据库
use test # 切换至 test 数据库

db 命令

使用 db 命令查看正在使用的数据库

db
# ============= Run Results ============= #
test

创建集合/数据库

这些操作在 BestGuo 数据库中

MongoDB 中没有直接创建数据库的命令,但是使用 use 命令之后,并且执行添加集合的操作,数据库才算是真正意义上的创建。

使用 db.createCollection() 方法来创建集合。

db.createCollection("user")

或者从一个不存在的集合中插入一个文档时,它也会自动创建该集合。插入文档的操作将在后面介绍。

db.user_2_0.insert({"name": "bestguo2020""age": 18})
/*********** Run Results ***********/
WriteResult({ "nInserted" : 1 })

删除集合

使用 db.collectionName.drop() 来删除集合,其中 collectionName 指的是集合名字。

db.user.drop()

插入文档

插入文档可以使用 db.collectionName.save() 方法和 db.collectionName.insert() 方法插入数据。

在插入整数时,由于 json 格式只有 number 类型,mongodb 为了保证不出错将 shell 中所有的 int、double 类型都存为 double。当然官方也考虑到用户实际想保存整型的问题,故允许在 json 中增加整型函数 NumberInt() 。

var data = [];

for(var i = 1; i < 11; i++) {
    data.push({
        "name": "德川" + i,
        "age": NumberInt(17 + i),
        "gender": "男",
        "phone": "0592-114514"
    })    
}

db.user_2_0.insertMany(data)

insert 方法

插入一条数据

db.user_2_0.save(
    {
        "name": "田所浩二",
        "age": 24,
        "gender": "男",
        "phone": "0592-114514"
    }
)

插入多条数据,由于 MongoDB 的 shell 界面是 JavaScript,因此可以编写 JavaScript 的代码。

var data = [];

for(var i = 0; i < 1000; i++) {
    data.push({
        "name": "德川" + i,
        "age": 42 + i,
        "gender": "男",
        "phone": "0592-114514"
    })    
}

db.user_2_0.insert(data)

/***** Run Results *****/
1000
Inserted 1 record(s) in 15ms

save 方法

db.user_2_0.save(
    {
        "name": "lisi",
        "age": 21,
        "gender": "男",
        "phone": "1145141919811"
    }
)

两个方法的区别:若指定的 id 存在时,save 方法会将原有的文档进行替换,不存在则和 insert 方法是一样的。

使用 save 方法

第一次插入的数据

db.user_2_0.save(
    {
        "_id": "114514",
        "name": "我修院",
        "age": 24,
        "gender": "男",
        "phone": "0592-114514"
    }
)

第二次插入的数据时,会有如下的提示信息。

db.user_2_0.save(
    {
        "_id": "114514",
        "name": "德川",
        "age": 24,
        "gender": "男",
        "phone": "0592-114514"
    }
)
/***** Run Results *****/
Updated 1 existing record(s) in 2ms

使用 insert 方法

再次插入数据时,会出现 duplicate key error collection 的错误信息。

db.user_2_0.insert(
    {
        "_id": "114514",
        "name": "德川",
        "age": 24,
        "gender": "男",
        "phone": "0592-114514"
    }
)
/***** Run Results *****/
E11000 duplicate key error collection: BestGuo.user_2_0 index: _id_ dup key: { _id: "114514" }

更新文档

使用 db.collectionName.update() 方法对文档进行更新。使用 $set 来修改原有文档的内容

db.user_2_0.update(
    // 修改的条件
    {
        "_id": "114514"
    }, 
    // 修改的内容
    {
        $set: {
            "name": "德川我修院"
        }
    }
)
/***** Run Results *****/
Updated 1 existing record(s) in 1ms

在使用 $set 更新时,如果文档中不存在这个属性则会将不存在的属性添加进来。

db.user_2_0.update(
    {
        "_id": "114514"
    }, 
    {
        $set: {
            "name": "德川我修院",
            "vip": true
        }
    }
)
/***** Run Results *****/
Updated 1 existing record(s) in 1ms

{
    "_id" : "114514",
    "name" : "德川我修院",
    "age" : 24.0,
    "gender" : "男",
    "phone" : "0592-114514",
    "vip" : true
}

查询文档

使用 db.collectionName.find() 方法来查询出文档数据。未限制条件时则查询出全部的数据。

> db.user_2_0.find()
{ "_id" : ObjectId("62b97a2e305de3247a4e89cc"), "name" : "bestguo2020", "age" : 18 }
{ "_id" : ObjectId("62b97eace2bf2e431a87d8f6"), "name" : "zhangsan", "age" : 18, "gender" : "男", "phone" : "1145141919810" }
{ "_id" : ObjectId("62b97f23e2bf2e431a87d8f7"), "name" : "lisi", "age" : 21, "gender" : "男", "phone" : "1145141919811" }
{ "_id" : ObjectId("62b97fd4e2bf2e431a87d8f8"), "name" : "田所浩二", "age" : 24, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : "114514", "name" : "德川我修院", "age" : 24, "gender" : "男", "phone" : "0592-114514", "vip" : true }
{ "_id" : ObjectId("62b984cfe2bf2e431a87d8f9"), "name" : "德川0", "age" : 42, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b984cfe2bf2e431a87d8fa"), "name" : "德川1", "age" : 43, "gender" : "男", "phone" : "0592-114514" }
Type "it" for more

使用 findOne() 方法查询出一条数据

> db.user_2_0.findOne()
{
        "_id" : ObjectId("62b97a2e305de3247a4e89cc"),
        "name" : "bestguo2020",
        "age" : 18
}

调用 pretty() 方法将文档以格式化之后展示出来。

> db.user_2_0.find().pretty()
{
        "_id" : ObjectId("62b97a2e305de3247a4e89cc"),
        "name" : "bestguo2020",
        "age" : 18
}
{
        "_id" : ObjectId("62b97eace2bf2e431a87d8f6"),
        "name" : "zhangsan",
        "age" : 18,
        "gender" : "男",
        "phone" : "1145141919810"
}
Type "it" for more

显示指定的字段

若要指定显示某些字段,可以在第二个参数中指定出想要的字段,不指定时则全部显示。若指定的字段不存在,则不显示。

db.user_2_0.find(
	{}, # 查询的条件
    { # 需要显示的字段
        name: 1, 
        age: 1, 
        asd: 1 # 这个字段不存在,就不显示
    }
)

AND 条件

AND 条件很简单,只需在 find 方法中传入 JSON 格式即可。比如我找一个 name 为”田所浩二“,age 为”24“的人。可以写成{name: "田所浩二", age: 24}。下面的语句可以理解成 where name = '田所浩二' and age = 24。第一层的{}所代表的就是 AND了。

> db.user_2_0.find(
...     {
...         name: "田所浩二",
...         age: 24
...     }
... )
# ============= Run Results ============= #
{ "_id" : ObjectId("62b97fd4e2bf2e431a87d8f8"), "name" : "田所浩二", "age" : 24, "gender" : "男", "phone" : "0592-114514" }

OR 条件

OR 条件需要使用 $or 来设置。下面的例子展示了查询姓名为”田所浩二“或者”德川我修院“的人。可以理解为where name = '田所浩二' or name = '德川我修院'

db.user_2_0.find(
    {
        $or: [
            {
                name: "田所浩二"
            },
            {
                name: "德川我修院"
            }
        ]
    }
)

操作符

MongoDB中条件操作符有:

  • (>) 大于(great than) - $gt
  • (<) 小于 (less than)- $lt
  • (>=) 大于等于(great than or equals)- $gte
  • (<= ) 小于等于(less than or equals)- $lte
great than

大于操作符 $gt,比如我要查询出大于 100 岁的人。

> db.user_2_0.find({
...     age: {
...         $gt: 100
...     }
... })
# ============= Run Results ============= #
{ "_id" : ObjectId("62b984cfe2bf2e431a87d934"), "name" : "德川59", "age" : 101,
"gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b984cfe2bf2e431a87d935"), "name" : "德川60", "age" : 102,
"gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b984cfe2bf2e431a87d936"), "name" : "德川61", "age" : 103,
"gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b984cfe2bf2e431a87d937"), "name" : "德川62", "age" : 104,
"gender" : "男", "phone" : "0592-114514" }
Type "it" for more
less than

小于操作符 $lt,查询出大于 30 小于 50 岁的人。

> db.user_2_0.find({
	age: { 
		$gt: 30, 
		$lt: 50 
	} 
})
# ============= Run Results ============= #
{ "_id" : ObjectId("62b984cfe2bf2e431a87d8f9"), "name" : "德川0", "age" : 42, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b984cfe2bf2e431a87d8fa"), "name" : "德川1", "age" : 43, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b984cfe2bf2e431a87d8fb"), "name" : "德川2", "age" : 44, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b984cfe2bf2e431a87d8fc"), "name" : "德川3", "age" : 45, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b984cfe2bf2e431a87d8fd"), "name" : "德川4", "age" : 46, "gender" : "男", "phone" : "0592-114514" }
Type "it" for more
great than or equals

大于等于操作符 $gte,比如我要查询出大于等于 200 岁,小于 210 岁的人。、

> db.user_2_0.find({
    age: {
        $gte: 200,
        $lt: 210
    }
})
# ============= Run Results ============= #
{ "_id" : ObjectId("62b984cfe2bf2e431a87d997"), "name" : "德川158", "age" : 200, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b984cfe2bf2e431a87d998"), "name" : "德川159", "age" : 201, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b984cfe2bf2e431a87d999"), "name" : "德川160", "age" : 202, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b984cfe2bf2e431a87d99a"), "name" : "德川161", "age" : 203, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b984cfe2bf2e431a87d99b"), "name" : "德川162", "age" : 204, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b984cfe2bf2e431a87d99c"), "name" : "德川163", "age" : 205, "gender" : "男", "phone" : "0592-114514" }
Type "it" for more
less than or equals

小于等于操作符 $gte,比如我要查询出大于 200 岁,小于等于 205 岁的人。

> db.user_2_0.find({
    age: {
        $gt: 200,
        $lte: 205
    }
})
# ============= Run Results ============= #
{ "_id" : ObjectId("62b984cfe2bf2e431a87d998"), "name" : "德川159", "age" : 201, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b984cfe2bf2e431a87d999"), "name" : "德川160", "age" : 202, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b984cfe2bf2e431a87d99a"), "name" : "德川161", "age" : 203, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b984cfe2bf2e431a87d99b"), "name" : "德川162", "age" : 204, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b984cfe2bf2e431a87d99c"), "name" : "德川163", "age" : 205, "gender" : "男", "phone" : "0592-114514" }

模糊查询

在 MongoDB 中没有专门的模糊查询关键字,但是可以使用正则的方式来实现模糊查询。

> db.user_2_0.find({
...     age: {
...         $gte: 200,
...         $lt: 205
...     },
...     name: /田所/
... })
# ============= Run Results ============= #
{ "_id" : ObjectId("62b985d9e2bf2e431a87dd7f"), "name" : "田所浩二158", "age" : 200, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b985d9e2bf2e431a87dd80"), "name" : "田所浩二159", "age" : 201, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b985d9e2bf2e431a87dd81"), "name" : "田所浩二160", "age" : 202, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b985d9e2bf2e431a87dd82"), "name" : "田所浩二161", "age" : 203, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b985d9e2bf2e431a87dd83"), "name" : "田所浩二162", "age" : 204, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b985f6e2bf2e431a87e167"), "name" : "田所浩二158", "age" : 200, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b985f6e2bf2e431a87e168"), "name" : "田所浩二159", "age" : 201, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b985f6e2bf2e431a87e169"), "name" : "田所浩二160", "age" : 202, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b985f6e2bf2e431a87e16a"), "name" : "田所浩二161", "age" : 203, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b985f6e2bf2e431a87e16b"), "name" : "田所浩二162", "age" : 204, "gender" : "男", "phone" : "0592-114514" }

联动

查询出名字为”田所浩二x“(x表示数字,比如田所浩二114、田所浩二115)这一类的姓名,且年龄 18 ~ 24 岁(不含 24 岁含 18 岁)或在 114 ~ 119 (都包含) 之间。

> db.user_2_0.find({
...     name: /田所浩二\d+$/,
...     $or: [
...         {
...             age: {
...                 $gt: 18,
...                 $lte: 24
...             }
...         },
...         {
...             age: {
...                 $gte: 114,
...                 $lte: 119
...             }
...         },
...     ]
... })
# ============= Run Results ============= #
{ "_id" : ObjectId("62b985d9e2bf2e431a87dd29"), "name" : "田所浩二72", "age" : 114, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b985d9e2bf2e431a87dd2a"), "name" : "田所浩二73", "age" : 115, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b985d9e2bf2e431a87dd2b"), "name" : "田所浩二74", "age" : 116, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b985d9e2bf2e431a87dd2c"), "name" : "田所浩二75", "age" : 117, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b985d9e2bf2e431a87dd2d"), "name" : "田所浩二76", "age" : 118, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62b985d9e2bf2e431a87dd2e"), "name" : "田所浩二77", "age" : 119, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62baa3dae2bf2e431a87e4ba"), "name" : "田所浩二19", "age" : 19, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62baa3dae2bf2e431a87e4bb"), "name" : "田所浩二20", "age" : 20, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62baa3dae2bf2e431a87e4bc"), "name" : "田所浩二21", "age" : 21, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62baa3dae2bf2e431a87e4bd"), "name" : "田所浩二22", "age" : 22, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62baa3dae2bf2e431a87e4be"), "name" : "田所浩二23", "age" : 23, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62baa3dae2bf2e431a87e4bf"), "name" : "田所浩二24", "age" : 24, "gender" : "男", "phone" : "0592-114514" }

删除文档

删除文档可以使用 remove 方法、deleteOne 方法和 deleteMany 方法。

使用 remove 删除一条文档,需要传入一个参数 {justOne: 1} ,若不传递或者设置成 0,则会删除集合中的全部文档。

> db.user_2_0.remove({}, {justOne: 1})
# ============= Run Results ============= #
WriteResult({ "nRemoved" : 1 })

使用 deleteOne 能达到删除一条数据的效果。remove 传入参数 {justOne: 1} 和 deleteOne 删除一条信息的规则是第一条数据。

> db.user_2_0.deleteOne({})
# ============= Run Results ============= #
{ "acknowledged" : true, "deletedCount" : 1 }

也可以按照条件删除元素,比如删除 114 ~ 514 岁(都包含)的人,使用 deleteOne 。

> db.user_2_0.deleteMany({
    age: {
        $gte: 114,
        $lte: 514,
    }
})
# ============= Run Results ============= #
{
    "acknowledged" : true,
    "deletedCount" : 1211.0
}

排序

排序使用 sort() 方法,该方法作用于查询之后。比如我要查询姓名为”田所浩二x“(x表示数字,比如田所浩二114、田所浩二115)这一类的姓名,且按年龄升序排序。使用 1 和 -1 来指定排序的方式,其中 1 为升序排列,而 -1 是用于降序排列。

> db.user_2_0.find({name: /田所浩二\d+$/}).sort({age: 1}).pretty();
# ============= Run Results ============= #
{
        "_id" : ObjectId("62baa3dae2bf2e431a87e4b9"),
        "name" : "田所浩二18",
        "age" : 18,
        "gender" : "男",
        "phone" : "0592-114514"
}
{
        "_id" : ObjectId("62baa3dae2bf2e431a87e4ba"),
        "name" : "田所浩二19",
        "age" : 19,
        "gender" : "男",
        "phone" : "0592-114514"
}
{
        "_id" : ObjectId("62baa3dae2bf2e431a87e4bb"),
        "name" : "田所浩二20",
        "age" : 20,
        "gender" : "男",
        "phone" : "0592-114514"
}
{
        "_id" : ObjectId("62baa3dae2bf2e431a87e4bc"),
        "name" : "田所浩二21",
        "age" : 21,
        "gender" : "男",
        "phone" : "0592-114514"
}
{
        "_id" : ObjectId("62baa3dae2bf2e431a87e4bd"),
        "name" : "田所浩二22",
        "age" : 22,
        "gender" : "男",
        "phone" : "0592-114514"
}
Type "it" for more

Limit 与 Skip

limit() 方法就是从查询的结果中取出前几条文档,skip() 方法就是从查询的结果中跳过几个文档,从第几个文档开始查询。

使用 limit 查询前 5 条数据。

> db.user_2_0.find({}).limit(5)
# ============= Run Results ============= #
{ "_id" : ObjectId("62babe68dc0663b7a70c6daf"), "name" : "德川1", "age" : 18, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62babe68dc0663b7a70c6db0"), "name" : "德川2", "age" : 19, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62babe68dc0663b7a70c6db1"), "name" : "德川3", "age" : 20, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62babe68dc0663b7a70c6db2"), "name" : "德川4", "age" : 21, "gender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62babe68dc0663b7a70c6db3"), "name" : "德川5", "age" : 22, "gender" : "男", "phone" : "0592-114514" }

使用 skip,跳过前两条数据,从第三条数据开始查询。

> db.user_2_0.find({}).skip(2)
# ============= Run Results ============= #
{ "_id" : ObjectId("62babe68dc0663b7a70c6db1"), "name" : "德川3", "age" : 20, "g
ender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62babe68dc0663b7a70c6db2"), "name" : "德川4", "age" : 21, "g
ender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62babe68dc0663b7a70c6db3"), "name" : "德川5", "age" : 22, "g
ender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62babe68dc0663b7a70c6db4"), "name" : "德川6", "age" : 23, "g
ender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62babe68dc0663b7a70c6db5"), "name" : "德川7", "age" : 24, "g
ender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62babe68dc0663b7a70c6db6"), "name" : "德川8", "age" : 25, "g
ender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62babe68dc0663b7a70c6db7"), "name" : "德川9", "age" : 26, "g
ender" : "男", "phone" : "0592-114514" }
{ "_id" : ObjectId("62babe68dc0663b7a70c6db8"), "name" : "德川10", "age" : 27, "
gender" : "男", "phone" : "0592-114514" }

limit 和 skip 方法联动可实现分页的功能,每一页有 4 条数据。要显示出 4 条数据 limit 一定是 4,每一页的话,就应该是 4 的倍数。

db.user_2_0.find({}).skip(0).limit(4)
db.user_2_0.find({}).skip(4).limit(4)
db.user_2_0.find({}).skip(8).limit(4)
#......
db.user_2_0.find({}).skip(4n).limit(4)

聚合

MongoDB 中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。和关系型数据库 MySQL 类似。MySQL 有很多聚合函数,在 MongoDB 中采用的方式是以 $函数名 的形式来表示的。

利用分组统计个数

在指定使用哪个字段分组时,记得要加上”$“

接下来使用 aggregate 来统计集合中”男“、”女“性别个数。

> db.user_2_0.aggregate(
	{
	    # $group 指的是将查询结果进行分组
		$group: {
			_id: "$gender", # 使用文档中的哪个字段进行分组
			gender_count: {
				$sum: NumberInt(1) # 使用 $sum 进行求和
			}
		}
	}
)
# ============= Run Results ============= #
{ "_id" : "女", "gender_count" : 6 }
{ "_id" : "男", "gender_count" : 10 }

为什么统计的时候,要写个 1 在这里?

gender_count: {
    $sum: NumberInt(1) # 使用 $sum 进行求和
}

若写成 0 或者 2 的时候,那么得出的结果是什么样的呢?

# ============= $sum: 2 ============= #
{ "_id" : "女", "gender_count" : 12 }
{ "_id" : "男", "gender_count" : 20 }
# ============= $sum: 0 ============= #
{ "_id" : "女", "gender_count" : 0 }
{ "_id" : "男", "gender_count" : 0 }

看到上面的结果,就明白了,这个设置 $sum: 1 的意义在于分组之后,性别”男“中有几个 1 ,性别”女“中有几个 1,但是这里出现了 10 个性别为”男“,所以 1 * 10 = 10 。通过设置 $sum: 1 可以统计个数。设置 $sum: 2 也就不难理解了。

上面的写法,在 SQL 语句中可以理解成

select gender, count(*) from user_2_0 group by gender

利用分组求平均值、最小值和最大值

平均值使用 $avg,最小值和最大值分别为 $min$max 。获取男女中的平均年龄、最大值和最小值。

db.user_2_0.aggregate([
    {
        $group: { # group 里面存着的是分组之后的字段
            _id: "$gender",
            # 最大年龄
            max_age: {
                $max: "$age" 
            },
            # 最小年龄
            min_age: {
                $min: "$age"
            },
            # 平均年龄
            avg_age: {
                $avg: "$age"
            }
        }
    }
])
# ============= Run Results ============= #
{ "_id" : "男", "max_age" : 27, "min_age" : 18, "avg_age" : 22.5 }
{ "_id" : "女", "max_age" : 23, "min_age" : 18, "avg_age" : 20.5 }

分组结果排序

若要对分组结果进行排序,不能直接调用 sort 方法,而是需要在聚合方法中加一个 $sort 即可,然后去指定分组之后的字段

db.user_2_0.aggregate([
    {
        $group: {
            _id: "$gender",
            max_age: {
                $max: "$age" 
            },
            min_age: {
                $min: "$age"
            },
            avg_age: {
                $avg: "$age"
            }
        }
    },
    {
        $sort: { # 排序
            avg_age: 1 # 指定分组之后的哪个字段进行排序
        }
    }
])
# ============= Run Results ============= #
{ "_id" : "女", "max_age" : 23, "min_age" : 18, "avg_age" : 20.5 }
{ "_id" : "男", "max_age" : 27, "min_age" : 18, "avg_age" : 22.5 }