基于 MongoDB 4.4.3

环境:Windows 10

关于安装

MongoDB服务(服务器)

  • 开启服务 / 数据文件存放路径 / 端口
mongod -dbpath D:\development\MongoDB\data\db --port 18080

以上设置在永久性服务中,需要另行配置

上述启动方法,每次启动否需要输入命令,所以建立一个永久性的服务,即加入到windows本地服务(系统服务)中

  • 安装MongoDB服务
D:\development\MongoDB\bin\mongod.exe --config "C:\development\MongoDB\mongod.cfg" --install
  • 启动MongoDB服务
net start MongoDB

启动前在bin目录下检查配置文件mongod.cfg,

# mongod.conf

# 存储数据
storage:
  dbPath: D:\development\MongoDB\data\db
  journal:
    enabled: true

# 日志数据
systemLog:
  destination: file
  logAppend: true
  path:  D:\development\MongoDB\log\mongod.log

# 网络接口
net:
  port: 27017
  bindIp: 127.0.0.1
  • 关闭MongoDB服务
net stop MongoDB
  • 移除 MongoDB 服务
mongod --remove

命令行(客户端)

  • 打开命令行(连接服务器)
mongo

基本概念

MongoDB面向文档数据库

数据库

  • MongoDB 单个实例可以有多个独立数据库,每个包含集合、权限,
  • 不同的数据库,放置在不同文件
  • 默认数据库 “db”,存储在 data 目录下

集合(表)

  • 集合在数据库中
  • 集合没有固定结构,可以插入不同格式、类型的数据(通常插入有关联性的数据)
  • 第一个 文档 插入时,集合就会被创建
{"site":"www.baidu.com"}  
{"site":"www.google.com","name":"Google"}  
{"site":"www.runoob.com","name":"菜鸟教程","num":5}

文档(行)

  • 对应 RDBMS(关系数据库管理系统:Relational Database Management System):“行”
  • 文档是键值对(BSON)
  • 文档不需要设置相同字段,相同字段不需要相同数据类型
{"site":"www.runoob.com", "name":"菜鸟教程"}

基本操作

数据库操作

  • show dbs: 显示所有数据库
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
  • db: 显示当前数据库 / 集合(表)。在 MongoDB 中默认数据库是:test。 如果没有创建过任何数据库,则集合/文档将存储在test数据库中。
> db
test
  • use: 连接到指定数据库 / 创建数据库。
    用法1: 切换数据库
> use local

用法2: 数据库名不存在,则创建数据库。

# 数据库创建成功,但是不能查询到
> use mytest
switched to db mytest
> db
mytest
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB

# 新建数据库需要插入数据才可以用 dbs 命令检索出来
# 在mytest数据库下新建 collectiontest 集合
> db.collectiontest.insert({"name":"test1"})
WriteResult({ "nInserted" : 1 })
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
mytest  0.000GB
> show collections
collectiontest
  • db.dropDatabase(): 删除数据库
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
mytest  0.000GB
> use mytest
switched to db mytest
> db.dropDatabase()
{ "dropped" : "mytest", "ok" : 1 }
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
>

集合操作

  • db.createCollection():
    在test数据库创建runoob集合,
> db
test
> show collections
> db.createCollection("runoob")
{ "ok" : 1 }
> show collections
runoob
  • db.createCollection(): 带参
    创建固定集合 mycol,整个集合空间大小 6142800 KB, 文档最大个数为 10000 个
> db.createCollection("mycol", { capped : true, autoIndexId : true, size : 6142800, max : 10000 } )
{ "ok" : 1 }
> show collections
mycol
runoob
>
  • show collections: 查看已有集合
> use test
switched to db test
> show collections
mycol
runoob
>
  • 集合如果不存在,在插入文档时,会自动创建集合
> use test
switched to db test
> db.mycol02.insert({"name":"runoob-test"})
WriteResult({ "nInserted" : 1 })
> show collections
mycol
mycol02
runoob
  • db..drop(): 删除集合
> show collections
mycol
mycol02
runoob
> db.mycol02.drop()
true
> show collections
mycol
runoob
>

文档操作

添加

  • db.collection.insert():
    向集合中插入一个或多个文档
    向集合插入文档时,如果没有给指定指定 _id 属性,则数据库会自动为文档添加,该属性用来作为文档的唯一标识
    _id 可以自己指定,这样数据库就不会自动添加了。自己指定的 _id 也必须唯一,否则报错
  • 插入一个文档
> db.stus.insert({name: "孙悟空", age: 20, gender: "男"});
WriteResult({ "nInserted" : 1 })
> db.stus.find();
{ "_id" : ObjectId("61b58a89e4b077ad0bb9c270"), "name" : "孙悟空", "age" : 20, "gender" : "男" }
>
  • 插入多个文档
> db.stus.insert([
...     {name: "猪八戒", age: 15, gender: "男"},
...     {name: "白骨精", age: 19, gender: "男"},
...     {name: "蜘蛛精", age: 16, gender: "女"}
... ]);
BulkWriteResult({
        "writeErrors" : [ ],
        "writeConcernErrors" : [ ],
        "nInserted" : 3,	// 新插入3条
        "nUpserted" : 0,
        "nMatched" : 0,
        "nModified" : 0,
        "nRemoved" : 0,
        "upserted" : [ ]
})
> db.stus.find();
{ "_id" : ObjectId("61b58a89e4b077ad0bb9c270"), "name" : "孙悟空", "age" : 20, "gender" : "男" }
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb1"), "name" : "猪八戒", "age" : 15, "gender" : "男" }
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb2"), "name" : "白骨精", "age" : 19, "gender" : "男" }
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb3"), "name" : "蜘蛛精", "age" : 16, "gender" : "女" }
>

_id 也可以自己生成,也可以自己指定

# 自己生成 
> ObjectId()
ObjectId("61b5d73d68ba54fa0c434669")
>

# 自己指定
> db.stus.insert({_id: 'hello123', name: "如来佛", age: 20, gender: "男"});
WriteResult({ "nInserted" : 1 })
> db.stus.find()
{ "_id" : ObjectId("61b58a89e4b077ad0bb9c270"), "name" : "孙悟空", "age" : 20, "gender" : "男" }
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb1"), "name" : "猪八戒", "age" : 15, "gender" : "男" }
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb2"), "name" : "白骨精", "age" : 19, "gender" : "男" }
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb3"), "name" : "蜘蛛精", "age" : 16, "gender" : "女" }
{ "_id" : "hello123", "name" : "如来佛", "age" : 20, "gender" : "男" }

# 自己指定的 _id 也必须唯一,否则报错
> db.stus.insert({_id: 'hello123', name: "如来佛", age: 20, gender: "男"});
WriteResult({
        "nInserted" : 0,
        "writeError" : {
                "code" : 11000,
                "errmsg" : "E11000 duplicate key error collection: test.stus index: _id_ dup key: { _id: \"hello123\" }"
        }
})
>
  • db.collection.insertOne():db.collection.insertMany():
    这两个方法是在 3.2 以后新加入的,分别用于 添加一个添加多个

查询

  • db.collection.find(): 参数是{},返回的是文档数组
    find():查询集合中所有符合条件的文档,可以接收一个对象作为条件参数
# 没有参数,或者传入一个空对象 {},表示查询所有文档
> db.stus.find();
> db.stus.find({});
{ "_id" : ObjectId("61b58a89e4b077ad0bb9c270"), "name" : "孙悟空", "age" : 20, "gender" : "男" }
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb1"), "name" : "猪八戒", "age" : 15, "gender" : "男" }
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb2"), "name" : "白骨精", "age" : 19, "gender" : "男" }
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb3"), "name" : "蜘蛛精", "age" : 16, "gender" : "女" }
{ "_id" : "hello123", "name" : "如来佛", "age" : 20, "gender" : "男" }
# { 属性名: 值 }
# 查询 _id 为 "hello123" 的文档
> db.stus.find({_id: "hello123"})
{ "_id" : "hello123", "name" : "如来佛", "age" : 20, "gender" : "男" }

# 查询 age==15 而且 gender==男
> db.stus.find({ age: 15, gender: "男"})
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb1"), "name" : "猪八戒", "age" : 15, "gender" : "男" }
>

查询操作符:

  • 比较操作符

操作符

描述

例子

$eq

等于

db.col.find({“by”: {$eq:“辛小花”}})

$ne

不等于

db.col.find({“by”: {$ne:“辛小花”}})

$gt

大于

db.col.find({“like”: {$gt: 3}})

$gte

大于等于

db.col.find({“like”: {$gte: 3}})

$lt

小于

db.col.find({“like”: {$lt: 120}})

$lte

小于等于

db.col.find({“like”: {$lte: 120}})

$in

在数组中

db.col.find({“by”: {$in: [“辛小花”, “黄仁宇”]}})

$nin

不在数组中

db.col.find({“by”: {$nin: [“辛小花”, “黄仁宇”]}})

  • 逻辑操作符

操作符

描述

例子

$and

逻辑与,

db.col.find({KaTeX parse error: Expected '}', got 'EOF' at end of input: and: [{"by": {in: [“辛小花”, “黄仁宇”]}}, {“like”: {$lt: 120}}]})

$or

逻辑或

db.col.find({KaTeX parse error: Expected '}', got 'EOF' at end of input: or: [{"by": {in: [“辛小花”, “黄仁宇”]}}, {“like”: {$lt: 120}}]})

$not

逻辑否

db.col.find({“by”: {$not: { $eq: “辛小花”}}})

$nor

同时不能匹配

db.col.find({KaTeX parse error: Expected '}', got 'EOF' at end of input: …花'}, {"like": {gt: 120}}]})

  • db.collection.findOne(): 参数是{},返回的是文档对象
> db.stus.find({ age: 20})             )
{ "_id" : ObjectId("61b58a89e4b077ad0bb9c270"), "name" : "孙悟空", "age" : 20, "gender" : "男" }
{ "_id" : "hello123", "name" : "如来佛", "age" : 20, "gender" : "男" }
> db.stus.findOne({ age: 20})
{
        "_id" : ObjectId("61b58a89e4b077ad0bb9c270"),
        "name" : "孙悟空",
        "age" : 20,
        "gender" : "男"
}
>
  • db.collection.find().count(): 计数,统计查询的结果有多少条
> db.stus.find( {} ).count()
5
>

修改

  • db.collection.update(): 更新文档
    参数:query:查询条件,类似where
    update:更新操作符,类似set
    upsert:不存在记录是否插入,true(插入),false(不插入,默认)
    multi:只更新一条,true(更新全部),false(默认)
    writeConcern:抛出异常级别
# db.collection.update(
 #   <query>,
 #   <update>,
 #   {
 #     upsert: <boolean>,
 #     multi: <boolean>,
 #     writeConcern: <document>
 #   }
 # )

update() 方法默认以新对象替换旧对象

# 原有的文档被替换了
> db.stus.update({ name: "孙悟空" }, {age: 15});
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.stus.find({});
{ "_id" : ObjectId("61b58a89e4b077ad0bb9c270"), "age" : 15 }
... ...
>

$set: 使用 update(修改操作符)修改指定属性而不替换

> db.stus.update(
    {name: "猪八戒"},
    {
        $set: {
            age: 16
        }
    }
)
Updated 1 existing record(s) in 1ms
> db.stus.find({name: "猪八戒"})
{"_id" : ObjectId("61b58cd8d00f32f85a47ddb1"), "name" : "猪八戒", "age" : 16.0, "gender" : "男"}

$unset: 删除文档指定属性

# age赋值无所谓,目的为移除属性
> db.stus.update(
    {name: "猪八戒"},
    {
        $unset: {
            age: "" 
        }
    }
)
Updated 1 existing record(s) in 1ms

# age属性没有了
> db.stus.find()
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb1"), "name" : "猪八戒", "gender" : "男" }
  • multi: update默认操作一个文档,multi: true 操作所有符合条件的文档
> db.stus.update(
    {gender: "男"},
    {
        $set: {
            age: "17" 
        }
    },
    {
        multi: true
    }
)
db.stus.find({name: "猪八戒"})

# 查看所有,发现 gender=="男" 的文档都被修改了
> db.stus.find()
{ "_id" : ObjectId("61b58a89e4b077ad0bb9c270"), "age" : 15 }
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb1"), "name" : "猪八戒", "gender" : "男", "age" : "17" }
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb2"), "name" : "白骨精", "age" : "17", "gender" : "男" }
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb3"), "name" : "蜘蛛精", "age" : 16, "gender" : "女" }
{ "_id" : "hello123", "name" : "如来佛", "age" : "17", "gender" : "男" }
>
  • $inc: 对数字属性增加值
> db.stus.update(
    {age: 15},
    {
        $inc: {
            age: 1 
        }
    }
)
Updated 1 existing record(s) in 1ms

# age==15 的文档,age增长1
> db.stus.find()
{ "_id" : ObjectId("61b58a89e4b077ad0bb9c270"), "age" : 16 }
  • $rename: 修改属性名称
> db.stus.update(
    {name: "如来佛"},
    {
        $rename: {
            age: "ageNum" 
        }
    }
)
Updated 1 existing record(s) in 1ms

# 属性名被修改了
> db.stus.find({name: "如来佛"})
{ "_id" : "hello123", "name" : "如来佛", "gender" : "男", "ageNum" : "17" }
>
  • $push: 给文档追加一个属性
> db.stus.find({age: 16})
{ "_id" : ObjectId("61b58a89e4b077ad0bb9c270"), "age" : 16 }
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb3"), "name" : "蜘蛛精", "age" : 16, "gender" : "女" }

# 给文档追加一个属性,此属性只能是数组,如果不存在,则添加一个属性,
> db.stus.update(
    {age: 16},
    {
        $push: {
            name: "孙悟空" 
        }
    }
)
Updated 1 existing record(s) in 1ms
> db.stus.find({age: 16})
{ "_id" : ObjectId("61b58a89e4b077ad0bb9c270"), "age" : 16, "name" : [ "孙悟空" ] }
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb3"), "name" : "蜘蛛精", "age" : 16, "gender" : "女" }
  • $addToSet: 加一个值到属性的数组内,而且只有当这个值在数组中不存在时才增加。
> db.stus.update(
    {name: "猪八戒"},
    {
        $addToSet: {
            food: "越多越好" 
        }
    }
)
Updated 1 existing record(s) in 1ms
> db.stus.findOne({name: "猪八戒"})
{
        "_id" : ObjectId("61b58cd8d00f32f85a47ddb1"),
        "name" : "猪八戒",
        "gender" : "男",
        "age" : "17",
        "food" : [
                "越多越好"		# 多次执行addToSet,只会有一个 "越多越好"
        ]
}

# 追加一个其他值,可以追加成功
> db.stus.update(
    {name: "猪八戒"},
    {
        $addToSet: {
            food: "多多益善" 
        }
    }
)
Updated 1 existing record(s) in 1ms
> db.stus.findOne({name: "猪八戒"})
{
        "_id" : ObjectId("61b58cd8d00f32f85a47ddb1"),
        "name" : "猪八戒",
        "gender" : "男",
        "age" : "17",
        "food" : [
                "越多越好",
                "多多益善"
        ]
}
>
  • $pull: 指定属性的数组内删除一个指定的值
# 多追加一个属性
> db.stus.update(
    {age: 16},
    {
        $push: {
            name: "孙行者" 
        }
    }
)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.stus.find({age: 16})
{ "_id" : ObjectId("61b58a89e4b077ad0bb9c270"), "age" : 16, "name" : [ "孙悟空", "孙行者" ] }
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb3"), "name" : "蜘蛛精", "age" : 16, "gender" : "女" }

# 从属性的数组内移除一个值
> db.stus.update(
    {age: 16},
    {
        $pull: {
            name: "孙悟空" 
        }
    }
)
Updated 1 existing record(s) in 2ms
> db.stus.find({age: 16})
{ "_id" : ObjectId("61b58a89e4b077ad0bb9c270"), "age" : 16, "name" : [ "孙行者" ] }
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb3"), "name" : "蜘蛛精", "age" : 16, "gender" : "女" }
>
  • $pop: 删除属性数组内的一个值
> db.stus.find({name: "猪八戒"})
{
    "_id" : ObjectId("61b58cd8d00f32f85a47ddb1"),
    "name" : "猪八戒",
    "gender" : "男",
    "age" : "17",
    "food" : [ 
        "越多越好", 
        "多多益善", 
        "一顿千金", 
        "吃穷唐僧"
    ]
}

# 删除数组第一个:  {$pop:{tags:-1}}		-1 -> 删除tags[0]
# 删除数组最后一个: {$pop:{tags:1}}
> db.stus.update(
    {name: "猪八戒"},
    {
        $pop: {
            food: 1 
        }
    }
)
> db.stus.find({name: "猪八戒"})
Updated 1 existing record(s) in 1ms
{
    "_id" : ObjectId("61b58cd8d00f32f85a47ddb1"),
    "name" : "猪八戒",
    "gender" : "男",
    "age" : "17",
    "food" : [ 
        "越多越好", 
        "多多益善", 
        "一顿千金"
    ]
}
  • 其他方法
  • db.collection.updateOne(): 修改一个
  • db.collection.updateMany(): 修改多个
  • db.collection.updatereplaceOne(): 替换

删除

  • db.collection.remove():
    传参和 find() 方法一样
> db.stus.find({})
{ "_id" : ObjectId("61b58a89e4b077ad0bb9c270"), "age" : 16, "name" : [ "孙行者" ] }
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb1"), "name" : "猪八戒", "gender" : "男", "age" : "17", "food" : [ "越多越好", "多多益善", "一顿千金" ] }
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb2"), "name" : "白骨精", "age" : "17", "gender" : "男" }
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb3"), "name" : "蜘蛛精", "age" : 16, "gender" : "女" }
{ "_id" : "hello123", "name" : "如来佛", "gender" : "男", "ageNum" : "17" }

# 根据条件删除
db.stus.remove(
    {name: "猪八戒"}
)
Removed 1 record(s) in 1ms
> db.stus.find({})
{ "_id" : ObjectId("61b58a89e4b077ad0bb9c270"), "age" : 16, "name" : [ "孙行者" ] }
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb2"), "name" : "白骨精", "age" : "17", "gender" : "男" }
{ "_id" : ObjectId("61b58cd8d00f32f85a47ddb3"), "name" : "蜘蛛精", "age" : 16, "gender" : "女" }
{ "_id" : "hello123", "name" : "如来佛", "gender" : "男", "ageNum" : "17" }
>
  • 删除所有
# 删除所有
> db.stus.remove({})
Removed 4 record(s) in 1ms
  • 其他方法
  • db.collection.deleteOne():
  • db.collection.deleteMany():

实战练习

  • 进入 my_test 数据库
> use my_test
switched to db my_test
>
  • 向数据库 user 集合中插入文档
> db.users.insert({username:"孙悟空"})
WriteResult({ "nInserted" : 1 })
>
  • 查询 user 集合中的文档
> db.users.find()
{ "_id" : ObjectId("61bac4d71d938538c23fce5f"), "username" : "孙悟空" }
>
  • 统计 user 集合中的文档数量
> db.users.find().count()
1
>
  • 查询 user 集合中 username 为 “孙悟空” 的文档
> db.users.find({username:"孙悟空"})
{ "_id" : ObjectId("61bac4d71d938538c23fce5f"), "username" : "孙悟空" }
>
  • 向 user 集合中 username 为 “孙悟空” 的文档添加一个 address属性,值为 “花果山”
> db.users.update({username:"孙悟空"}, {$set:{address:"花果山"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
  • 用 {username: “唐僧”} 替换 username 为 “猪八戒” 的文档
> db.users.insert({username:"猪八戒"})
WriteResult({ "nInserted" : 1 })
> db.users.find()
{ "_id" : ObjectId("61bac4d71d938538c23fce5f"), "username" : "孙悟空", "address" : "花果山" }
{ "_id" : ObjectId("61bac83f1d938538c23fce60"), "username" : "猪八戒" }
> db.users.replaceOne({username:"猪八戒"}, {username: "唐僧"})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find()
{ "_id" : ObjectId("61bac4d71d938538c23fce5f"), "username" : "孙悟空", "address" : "花果山" }
{ "_id" : ObjectId("61bac83f1d938538c23fce60"), "username" : "唐僧" }
>
  • 删除 username 为 “孙悟空” 的文档的 address 属性
> db.users.update({username: "孙悟空"}, {$unset:{address: 1}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.find({username:"孙悟空"})
{ "_id" : ObjectId("61bac4d71d938538c23fce5f"), "username" : "孙悟空" }
>
  • 给 username 为 “孙悟空” 的文档添加一个 hobby 属性
    当一个文档的属性值是一个文档时,称这个内部的文档叫内嵌文档
> db.users.update(
	{username: "孙悟空"}, 
	{$set: {hobby: {cities: ["北京","上海","深圳"], movies: ["复仇者联盟","加勒比海盗"]}}}
)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.find({username:"孙悟空"})
{
    "_id" : ObjectId("61bac4d71d938538c23fce5f"),
    "username" : "孙悟空",
    "hobby" : {
        "cities" : [ 
            "北京", 
            "上海", 
            "深圳"
        ],
        "movies" : [ 
            "复仇者联盟", 
            "加勒比海盗"
        ]
    }
}

给 username 为 “唐僧” 的文档,添加一个属性

> db.users.update(
	{username: "唐僧"}, 
	{$set: {hobby: {movies: ["红楼梦","女儿国"]}}}
)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
  • 查询喜欢电影 “复仇者联盟” 的文档
# mongoDB支持通过内嵌文档的属性查询,通过 . 的形式
# 根据内嵌文档属性查询,属性名必须使用引号
# movies是数组,里面有一个元素可以匹配,就可以查询成功
> db.users.find({"hobby.movies":"复仇者联盟"})
{ "_id" : ObjectId("61bac4d71d938538c23fce5f"), "username" : "孙悟空", "hobby" : { "cities" : [ "北京", "上海", "深圳" ], "movies" : [ "复仇者联盟", "加勒比海盗" ] } }
>
  • 向 “唐僧” 文档中添加一个新的电影 “大闹天竺”
# $push			用于向数组添加一个新的元素,不考虑重复
# $addToSet		用于向数组添加一个新的元素,只能添加不存在的元素
> db.users.update({username:"唐僧"}, {$push:{"hobby.movies":"大闹天竺"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
  • 删除喜欢 “北京” 的文档
> db.users.remove({"hobby.cities": "北京"})
WriteResult({ "nRemoved" : 1 })
>
  • 删除 users 集合
# 方法一:更像清空集合
> db.users.remove({})
WriteResult({ "nRemoved" : 1 })
> 
# 方法二:
> db.users.drop()
true
>
  • 向 numbers 集合中插入 20000 条数据
    结果显示的是最后一条的时间
for(var i = 1; i <= 20000; i++) {
    db.numbers.insert({num: i})
}
Inserted 1 record(s) in 7.2s

可以提高插入速度,先插入数组,在把数组插入集合(IO速度:内存 > 硬盘)

var arr = [];
for(var i = 1; i <= 20000; i++) {
    arr.push({num: i})
}
db.numbers.insert(arr)
Inserted 1 record(s) in 206ms
  • 查询 numbers 集合中 num 大于 5000 的文档
# $gt	大于
# $gte	大于等于
# $lt	小于
# $lte	小于等于
# $eq	等于
# $ne	不等于
> db.numbers.find({num: {$gt: 5000}})
{ "_id" : ObjectId("61bb35ff15a563aa27c0b681"), "num" : 5001 }
{ "_id" : ObjectId("61bb35ff15a563aa27c0b682"), "num" : 5002 }
{ "_id" : ObjectId("61bb35ff15a563aa27c0b683"), "num" : 5003 }
{ "_id" : ObjectId("61bb35ff15a563aa27c0b684"), "num" : 5004 }
... ...
  • 查询 numbers 集合中 num 大于 40,小于 50 的文档
> db.numbers.find({num: {$gt: 40, $lt: 50}})
{ "_id" : ObjectId("61bb35ff15a563aa27c0a321"), "num" : 41 }
... ...
{ "_id" : ObjectId("61bb35ff15a563aa27c0a329"), "num" : 49 }
>
  • 查询 numbers 集合中的前 10 条数据
> db.numbers.find().limit(10)
{ "_id" : ObjectId("61bb35ff15a563aa27c0a2f9"), "num" : 1 }
{ "_id" : ObjectId("61bb35ff15a563aa27c0a2fa"), "num" : 2 }
... ...
  • 查看 numbers 集合中第 11 到第 20 条数据(第二页)
# db.numbers.find().skip((页码-1)*每页条数).limit(每页条数)
> db.numbers.find().skip(10).limit(10)
{ "_id" : ObjectId("61bb35ff15a563aa27c0a303"), "num" : 11 }
{ "_id" : ObjectId("61bb35ff15a563aa27c0a304"), "num" : 12 }
{ "_id" : ObjectId("61bb35ff15a563aa27c0a305"), "num" : 13 }
{ "_id" : ObjectId("61bb35ff15a563aa27c0a306"), "num" : 14 }
{ "_id" : ObjectId("61bb35ff15a563aa27c0a307"), "num" : 15 }
{ "_id" : ObjectId("61bb35ff15a563aa27c0a308"), "num" : 16 }
{ "_id" : ObjectId("61bb35ff15a563aa27c0a309"), "num" : 17 }
{ "_id" : ObjectId("61bb35ff15a563aa27c0a30a"), "num" : 18 }
{ "_id" : ObjectId("61bb35ff15a563aa27c0a30b"), "num" : 19 }
{ "_id" : ObjectId("61bb35ff15a563aa27c0a30c"), "num" : 20 }
>
  • 将 json 格式的数据文件导入到 mongodb 数据库
# --host[h]				主机
# --port				端口
# -db[d]				目标数据库
# -username[u]			用户名
# -password[p]			密码
# -collection[c]		目标Collection,不指定则采用文件名称
# --numInsertionWorkers	并发数
# --file				目标导入文件
# -legacy				识别json v1.0,MongoDB4.2以后,识别{"_id":{"$oid":"5be19b932ab79c00013074ed"}}

# 导入部门
**\bin> mongoimport --host 127.0.0.1 --port 27017 -d my_test -c dept --file "e:\dept.json" --legacy
2021-12-17T11:00:41.780+0800    connected to: mongodb://127.0.0.1:27017/
2021-12-17T11:00:42.064+0800    4 document(s) imported successfully. 0 document(s) failed to import.
> db.dept.find()
{ "_id" : ObjectId("5941f2bac1bc86928f4de49a"), "deptno" : 10, "dname" : "财务部", "loc" : "北京" }
{ "_id" : ObjectId("5941f2bac1bc86928f4de49b"), "deptno" : 20, "dname" : "办公室", "loc" : "上海" }
{ "_id" : ObjectId("5941f2bac1bc86928f4de49c"), "deptno" : 30, "dname" : "销售部", "loc" : "广州" }
{ "_id" : ObjectId("5941f2bac1bc86928f4de49d"), "deptno" : 40, "dname" : "运营部", "loc" : "深圳" }
>

# 导入人员
**\bin> mongoimport --host 127.0.0.1 --port 27017 -d my_test -c emp --file "e:\emp.json" --legacy
2021-12-17T11:07:09.970+0800    connected to: mongodb://127.0.0.1:27017/
2021-12-17T11:07:10.248+0800    14 document(s) imported successfully. 0 document(s) failed to import.
> db.emp.find()
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4ac"), "empno" : 7369, "ename" : "林冲", "job" : "职员", "mgr" : "7902", "hiredate" : ISODate("1980-12-16T16:00:00Z"), "sal" : 800, "deptno" : 20 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4af"), "empno" : 7566, "ename" : "卢俊义", "job" : "经理", "mgr" : "7839", "hiredate" : ISODate("1981-04-01T16:00:00Z"), "sal" : 2975, "deptno" : 20 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4ad"), "empno" : 7499, "ename" : "孙二娘", "job" : "销售", "mgr" : "7698", "hiredate" : ISODate("1981-02-19T16:00:00Z"), "sal" : 1600, "deptno" : 30, "comm" : 300 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4ae"), "empno" : 7521, "ename" : "扈三娘", "job" : "销售", "mgr" : "7698", "hiredate" : ISODate("1981-02-21T16:00:00Z"), "sal" : 1250, "deptno" : 30, "comm" : 500 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b1"), "empno" : 7698, "ename" : "西门庆", "job" : "经理", "mgr" : "7839", "hiredate" : ISODate("1981-04-30T16:00:00Z"), "sal" : 2850, "deptno" : 30 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b2"), "empno" : 7782, "ename" : "柴进", "job" : "经理", "mgr" : "7839", "hiredate" : ISODate("1981-06-08T16:00:00Z"), "sal" : 2450, "deptno" : 10 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b3"), "empno" : 7788, "ename" : "公孙胜", "job" : "分析师", "mgr" : "7566", "hiredate" : ISODate("1987-07-12T16:00:00Z"), "sal" : 3000, "deptno" : 20 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b0"), "empno" : 7654, "ename" : "潘金莲", "job" : "销售", "mgr" : "7698", "hiredate" : ISODate("1981-09-27T16:00:00Z"), "sal" : 1250, "deptno" : 30, "comm" : 1400 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b4"), "empno" : 7839, "ename" : "宋江", "job" : "董事长", "hiredate" : ISODate("1981-11-16T16:00:00Z"), "sal" : 5000, "deptno" : 10 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b5"), "empno" : 7844, "ename" : "阎婆惜", "job" : "销售", "mgr" : "7698", "hiredate" : ISODate("1981-09-07T16:00:00Z"), "sal" : 1500, "deptno" : 30, "comm" : 0 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b6"), "empno" : 7876, "ename" : "李逵", "job" : "职员", "mgr" : "7902", "hiredate" : ISODate("1987-07-12T16:00:00Z"), "sal" : 1100, "deptno" : 20 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b9"), "empno" : 7934, "ename" : "鲁智深", "job" : "职员", "mgr" : "7782", "hiredate" : ISODate("1982-01-22T16:00:00Z"), "sal" : 1300, "deptno" : 10 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b7"), "empno" : 7900, "ename" : "武松", "job" : "职员", "mgr" : "7782", "hiredate" : ISODate("1981-12-02T16:00:00Z"), "sal" : 950, "deptno" : 10 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b8"), "empno" : 7902, "ename" : "吴用", "job" : "分析师", "mgr" : "7566", "hiredate" : ISODate("1981-12-02T16:00:00Z"), "sal" : 3000, "deptno" : 20 }
>
  • 查询工资 “sal” 在 1000~2000 直接的员工
> db.emp.find({sal: {$gt: 1000, $lt: 2000}})
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4ad"), "empno" : 7499, "ename" : "孙二娘", "job" : "销售", "mgr" : "7698", "hiredate" : ISODate("1981-02-19T16:00:00Z"), "sal" : 1600, "deptno" : 30, "comm" : 300 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4ae"), "empno" : 7521, "ename" : "扈三娘", "job" : "销售", "mgr" : "7698", "hiredate" : ISODate("1981-02-21T16:00:00Z"), "sal" : 1250, "deptno" : 30, "comm" : 500 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b0"), "empno" : 7654, "ename" : "潘金莲", "job" : "销售", "mgr" : "7698", "hiredate" : ISODate("1981-09-27T16:00:00Z"), "sal" : 1250, "deptno" : 30, "comm" : 1400 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b5"), "empno" : 7844, "ename" : "阎婆惜", "job" : "销售", "mgr" : "7698", "hiredate" : ISODate("1981-09-07T16:00:00Z"), "sal" : 1500, "deptno" : 30, "comm" : 0 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b6"), "empno" : 7876, "ename" : "李逵", "job" : "职员", "mgr" : "7902", "hiredate" : ISODate("1987-07-12T16:00:00Z"), "sal" : 1100, "deptno" : 20 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b9"), "empno" : 7934, "ename" : "鲁智深", "job" : "职员", "mgr" : "7782", "hiredate" : ISODate("1982-01-22T16:00:00Z"), "sal" : 1300, "deptno" : 10 }
>
  • 查询工资 “sal” 小于 1000 或者大于 2500 的员工
> db.emp.find({$or: [{sal: {$lt: 1000}}, {sal: {$gt: 2500}}]});
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4ac"), "empno" : 7369, "ename" : "林冲", "job" : "职员", "mgr" : "7902", "hiredate" : ISODate("1980-12-16T16:00:00Z"), "sal" : 800, "deptno" : 20 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4af"), "empno" : 7566, "ename" : "卢俊义", "job" : "经理", "mgr" : "7839", "hiredate" : ISODate("1981-04-01T16:00:00Z"), "sal" : 2975, "deptno" : 20 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b1"), "empno" : 7698, "ename" : "西门庆", "job" : "经理", "mgr" : "7839", "hiredate" : ISODate("1981-04-30T16:00:00Z"), "sal" : 2850, "deptno" : 30 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b3"), "empno" : 7788, "ename" : "公孙胜", "job" : "分析师", "mgr" : "7566", "hiredate" : ISODate("1987-07-12T16:00:00Z"), "sal" : 3000, "deptno" : 20 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b4"), "empno" : 7839, "ename" : "宋江", "job" : "董事长", "hiredate" : ISODate("1981-11-16T16:00:00Z"), "sal" : 5000, "deptno" : 10 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b7"), "empno" : 7900, "ename" : "武松", "job" : "职员", "mgr" : "7782", "hiredate" : ISODate("1981-12-02T16:00:00Z"), "sal" : 950, "deptno" : 10 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b8"), "empno" : 7902, "ename" : "吴用", "job" : "分析师", "mgr" : "7566", "hiredate" : ISODate("1981-12-02T16:00:00Z"), "sal" : 3000, "deptno" : 20 }
>
  • 查询财务部所有员工
> var deptno = db.dept.findOne({dname: "财务部"}).deptno;
> db.emp.find({deptno: deptno});
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b2"), "empno" : 7782, "ename" : "柴进", "job" : "经理", "mgr" : "7839", "hiredate" : ISODate("1981-06-08T16:00:00Z"), "sal" : 2450, "deptno" : 10 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b4"), "empno" : 7839, "ename" : "宋江", "job" : "董事长", "hiredate" : ISODate("1981-11-16T16:00:00Z"), "sal" : 5000, "deptno" : 10 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b9"), "empno" : 7934, "ename" : "鲁智深", "job" : "职员", "mgr" : "7782", "hiredate" : ISODate("1982-01-22T16:00:00Z"), "sal" : 1300, "deptno" : 10 }
{ "_id" : ObjectId("5941f5bfc1bc86928f4de4b7"), "empno" : 7900, "ename" : "武松", "job" : "职员", "mgr" : "7782", "hiredate" : ISODate("1981-12-02T16:00:00Z"), "sal" : 950, "deptno" : 10 }
>
  • 所有工资低于 1000 的员工,涨工资 400
> db.emp.updateMany({sal: {$lt:1000}}, {$inc: {sal: 400}})
{ "acknowledged" : true, "matchedCount" : 2, "modifiedCount" : 2 }
>

文档之间的关系

一对一(one to one)

可以通过内嵌文档的形式体现

db.wifeAndHusband.insert(
    {
        name: "黄蓉",
        husband: {
            name: "郭靖"
        }
    },{
        name: "潘金莲",
        husband: {
            name: "武大郎"
        }
    }
)
Inserted 1 record(s) in 264ms

一对多(one to many)/多对一(many to one)

用户(user)和订单(order)

# 用户
> db.users.insert([
    {name: "张三"}, 
    {name: "李四"}
])
Inserted 1 record(s) in 156ms
> db.users.find()
{ "_id" : ObjectId("61bb541615a563aa27c0f11c"), "name" : "张三" }
{ "_id" : ObjectId("61bb541615a563aa27c0f11d"), "name" : "李四" }
# 订单
db.order.insert({
    list: ["香蕉","苹果","鸭梨"],
    user_id: ObjectId("61bb541615a563aa27c0f11c")
})
db.order.insert({
    list: ["西瓜","香蕉"],
    user_id: ObjectId("61bb541615a563aa27c0f11c")
})
db.order.insert({
    list: ["牛肉","锅巴"],
    user_id: ObjectId("61bb541615a563aa27c0f11d")
})
> db.order.find()
{ "_id" : ObjectId("61bb54b215a563aa27c0f11e"), "list" : [ "香蕉", "苹果", "鸭梨" ], "user_id" : ObjectId("61bb541615a563aa27c0f11c") }
{ "_id" : ObjectId("61bb551315a563aa27c0f11f"), "list" : [ "西瓜", "香蕉" ], "user_id" : ObjectId("61bb541615a563aa27c0f11c") }
{ "_id" : ObjectId("61bb554f15a563aa27c0f120"), "list" : [ "牛肉", "锅巴" ], "user_id" : ObjectId("61bb541615a563aa27c0f11d") }
>

查找用户 “张三” 的订单

> var user_id = db.users.findOne({name: "张三"})._id;
> db.order.find({user_id: user_id})
{ "_id" : ObjectId("61bb54b215a563aa27c0f11e"), "list" : [ "香蕉", "苹果", "鸭梨" ], "user_id" : ObjectId("61bb541615a563aa27c0f11c") }
{ "_id" : ObjectId("61bb551315a563aa27c0f11f"), "list" : [ "西瓜", "香蕉" ], "user_id" : ObjectId("61bb541615a563aa27c0f11c") }
>

多对多(many to many)

老师(teacher)和学生(student)

# 老师
db.teacher.insert([
    {name: "洪七公"}, 
    {name: "黄药师"},
    {name: "龟仙人"}
])
> db.teacher.find()
{ "_id" : ObjectId("61bb584e15a563aa27c0f121"), "name" : "洪七公" }
{ "_id" : ObjectId("61bb584e15a563aa27c0f122"), "name" : "黄药师" }
{ "_id" : ObjectId("61bb584e15a563aa27c0f123"), "name" : "龟仙人" }
>
# 学生
db.student.insert([
    {
        name: "郭靖",
        tech_ids: [
            ObjectId("61bb584e15a563aa27c0f121"),
            ObjectId("61bb584e15a563aa27c0f122")
        ]
    },{
    	name: "孙悟空",
        tech_ids: [
            ObjectId("61bb584e15a563aa27c0f121"),
            ObjectId("61bb584e15a563aa27c0f122"),
            ObjectId("61bb584e15a563aa27c0f123")
        ]
    }
])
> db.student.find()
{ "_id" : ObjectId("61bb58fe15a563aa27c0f124"), "name" : "郭靖", "tech_ids" : [ ObjectId("61bb584e15a563aa27c0f121"), ObjectId("61bb584e15a563aa27c0f122") ] }
{ "_id" : ObjectId("61bb58fe15a563aa27c0f125"), "name" : "孙悟空", "tech_ids" : [ ObjectId("61bb584e15a563aa27c0f121"), ObjectId("61bb584e15a563aa27c0f122"), ObjectId("61bb5
84e15a563aa27c0f123") ] }
>

排序和投影

  • 查询文档时,默认是以 _id 升序排列,可以使用 sort() 指定排序规则
# 1标识升序,-1标识降序
> db.emp.find({}).sort({sal:1, empno:-1})
  • 查询时,可以用第二个参数,设置查询结果的投影
# _id是默认显示的
> db.emp.find({},{_id:0, ename:1, sal:1})
{ "ename" : "卢俊义", "sal" : 2975 }
{ "ename" : "孙二娘", "sal" : 1600 }
... ...
>

Mongoose

简介

Mongoose 是一个可以通过 Node 来操作 MongoDB 的模块。Mongoose 是一个对象文档模型(ODM)库,它对 Node 原生的 MongoDB 模块进一步的优化封装,并提供了更多的功能。

mongoose 的好处:

  • 可以为文档创建一个模式结构(Schema),或者说一个约束。
  • 可以对模型中的对象/文档进行验证
  • 数据可以通过类型转换为对象模型
  • 可以使用中间件来应用业务逻辑挂钩
  • 比 Node 原生的 MongoDB 驱动更容易

mongoose 中提供了几个新的对象

  • Schema(模式对象):定义了数据库中的文档结构
  • Model:作为集合中所有文档的表示,相当于 MongoDB 数据库中的集合 collection
  • Document:表示集合中具体的文档,相当于集合中的一个具体文档

测试:

  1. 环境准备
    新建目录,在目录下新建 package.json
{
	"name": "helloMongoose",
	"version": "0.0.1",
}
  1. 下载安装 mongoose,在新建的目录下执行命令:
npm i mongoose --save
  1. 新建 helloMongoose.js 文件
/**
  * 1. 下载安装 mongoose
  *       npm i mongoose --save
  * 
  * 2. 引入 mongoose
  * 
  * 3. 连接 MongoDB 数据库,新版本MongoDB需要加参数{useMongoClient: true}
  *       mongoose.connect('mongodb://ip:port/dbName', {useMongoClient: true})
  *       如果是默认端口(27017)可以省略
  * 
  * 4. 断开数据库连接(一般不需要调用)
  *       MongoDB 数据库,在一般情况下,只需要连接一次,除非项目停止服务器关闭,否则一般不会断开
  *       mongoose.disconnect()
  * 
  * 5. 监听 MongoDB 数据库的连接状态
  *       在 mongoose 对象中,有一个 connection 属性,该属性表示的就是数据库连接
  *       通过监视该对象的状态,可以监听数据库的连接、断开
  * 
  *       数据库连接成功的事件
  *       mongoose。connection。once("open", function(){})
  * 
  *       数据库断开的事件
  *       mongoose。connection。once("close", function(){})
  */

  // 引入
  var mongoose = require("mongoose");

  // 连接
  mongoose.connect('mongodb://127.0.0.1/mongoose_test');

  // 监听连接
  mongoose.connection.once('open', function(){
    console.log("数据库连接成功~~~");
  });

  // 监听断开
  mongoose.connection.once('close', function(){
    console.log("数据库连接已经断开~~~");
  })

  // 断开
  mongoose.disconnect();
  1. 运行
**> node .\helloMongoose.js
数据库连接成功~~~
数据库连接已经断开~~~

Schema 和 Model

  • 文件 helloSchema.js
var mongoose = require("mongoose");
 mongoose.connect('mongodb://127.0.0.1/mongoose_test');
 mongoose.connection.once("open", function(){
   console.log("数据库连接成功~~~");
 });

 /**
  * Schema
  */

 // 将 mongoose.Schema 赋值给一个变量
 var Schema = mongoose.Schema;

 // 创建 Schema (模式/约束)对象
 var stuSchema = new Schema({
    name: String,
    age: Number,
    gender: {
      type: String,
      default: "female"
    },
    address: String
 });

 // 通过 Schema 创建 Model
 // Model 代表数据库中的集合,通过 Model 才能对数据库进行操作
 // 语法:mongoose.model(modelName, schema);
 // 其中 modelName 是映射的集合名,MongoDB 会自动将单数改为复数
 var StuModel = mongoose.model("student", stuSchema);

 // 向数据库插入一个文档
 StuModel.create({
   name: "孙悟空",
   age: 18,
   gender: "male",
   address: "花果山"
 }, function(err){
   if(!err){
     console.log("插入成功~~~");
   }
 });
  • 运行
**\helloMongoose> node .\helloSchema.js
数据库连接成功~~~
插入成功~~~

Model 的方法

操作 Model,对数据库进行增删改查

新增

  • Model.crate(doc(s), [callback])
    用来创建一个或多个文档添加到数据库中
    参数:
  • doc(s) 可以是一个文档对象,也可以是一个文档对象的数组
  • callback 回调函数
StuModel.create([
  {
    name: "猪八戒",
    age: 28,
    gender: "male",
    address: "高老庄"
  },{
    name: "唐僧",
    age: 17,
    gender: "male",
    address: "东土大唐"
  }
], function(err){
  if(!err){
    console.log("插入成功~~~");
  }
});
  • 探究一下,回调函数的返回值
StuModel.create([
  {
    name: "沙和尚",
    age: 38,
    gender: "male",
    address: "流沙河"
  }
], function(err){
  if(!err){
    console.log(arguments);
  }
});
/*
**\helloMongoose> node .\helloModel.js
数据库连接成功~~~
[Arguments] {
  '0': null,	# err
  '1': [		# 插入的文档
    {
      name: '沙和尚',
      age: 38,
      gender: 'male',
      address: '流沙河',
      _id: new ObjectId("61bd3f924545d40f7c4ac800"),
      __v: 0
    }
  ]
}
*/

查询

  • Model.find(conditions, [projection], [options], [callback]) :查询所有符合条件的文档
  • Model.findById(id, [projection], [options], [callback]) :根据文档的ID查询文档
  • Model.findOne([conditions], [projection], [options], [callback]) :查询符合条件的第一个文档
  • conditions:查询条件
  • projection:投影
  • options:查询选项(skip、limit)
  • callback:回调函数,查询结果通过回调函数返回
  • 条件查询
// 查询所有符合条件的文档
StuModel.find({name: "唐僧"}, function(err, docs){
  if(!err) {
    console.log(docs);
  }
});
/*
返回结果是数组
[
  {
    _id: new ObjectId("61bd3e1885eebfa86f8a2e04"),
    name: '唐僧',
    age: 17,
    gender: 'male',
    address: '东土大唐',
    __v: 0
  }
]
*/

// 查询符合条件的第一个文档
StuModel.findOne({}, function(err, doc){
  if(!err) {
    console.log(doc);
  }
});
/*
返回结果是对象
{
  _id: new ObjectId("61bc9aef975b266f07bb657e"),
  name: '孙悟空',
  age: 18,
  gender: 'male',
  address: '花果山',
  __v: 0
}
*/

// 根据文档的ID查询文档
StuModel.findById("61bd3e1885eebfa86f8a2e04", function(err, doc){
  if(!err) {
    console.log(doc);
  }
});
/*
返回结果是对象
{
  _id: new ObjectId("61bd3e1885eebfa86f8a2e04"),
  name: '唐僧',
  age: 17,
  gender: 'male',
  address: '东土大唐',
  __v: 0
}
*/
  • 投影
// 方式一:{_id:0, name:1}
// 方式二:"-_id name"
StuModel.find({}, {_id:0,name:1}, function(err, docs){
  if(!err) {
    console.log(docs);
  }
});
/*
[
  { name: '孙悟空' },
  { name: '白骨精' },
  { name: '猪八戒' },
  { name: '唐僧' },
  { name: '沙和尚' }
]
*/


StuModel.find({}, "-_id name age", function(err, docs){
  if(!err) {
    console.log(docs);
  }
});
/*
[
  { name: '孙悟空', age: 18 },
  { name: '白骨精', age: 18 },
  { name: '猪八戒', age: 28 },
  { name: '唐僧', age: 17 },
  { name: '沙和尚', age: 38 }
]
*/
  • 查询选项
StuModel.find({}, "-_id name age", {skip:3, limit:1},function(err, docs){
  if(!err) {
    console.log(docs);
  }
});
/*
[ { name: '唐僧', age: 17 } ]
*/
  • Document 对象是 Model 的实例
StuModel.findOne({}, function(err, doc){
  if(!err) {
    console.log(doc instanceof StuModel);
  }
});
/*
true
*/

修改

  • Model.update(conditions, doc, [options], [callback])
  • Model.updateMany(conditions, doc, [options], [callback])
  • Model.updateOne(conditions, doc, [options], [callback])
  • conditions:查询条件
  • doc:修改后的文档
  • options:配置参数
  • callback:回调函数
  • 修改
StuModel.updateOne({name: "唐僧"}, {$set: {age: 20}}, function(err){
  if(!err){
    console.log("修改成功~~~");
  }
});

删除

  • Model.remove(conditions, [callback])
  • Model.deleteOne(conditions, [callback])
  • Model.deleteMany(conditions, [callback])
  • 删除
StuModel.remove({name: "白骨精"}, function(err){
  if(!err){
    console.log("删除成功~~~");
  }
});
# 根据返回值,remove已经被废除,建议使用 deleteOne, deleteMany
**\helloMongoose> node .\helloModel.js
数据库连接成功~~~
(node:73468) [MONGODB DRIVER] Warning: collection.remove is deprecated. Use deleteOne, deleteMany, or bulkWrite instead.
删除成功~~~

计数

  • Model.count(conditions, [callback])
  • 计数
StuModel.count({}, function(err, count){
  if(!err){
    console.log(count);
  }
});

Document 的方法

新增

  • 创建一个 Document
var StuModel = mongoose.model("student", stuSchema);

// 创建一个 Document
var stu = new StuModel({
  name: "奔波霸",
  age: 40,
  gender: "male",
  address: "碧波潭"
});
  • 保存
stu.save(function(err){
  if(!err){
    console.log("保存成功~~~");
  }
});

修改

  • 直接修改已经存在的数据
StuModel.findOne({}, function(err, doc){
  if(!err){
    doc.update({$set: {age:26}}, function(err){
      if(!err) {
        console.log("修改成功~~~");
      }
    })
  }
});
/*
# 可以看到,update方法已经过时,建议使用updateOne, updateMany。
PS E:\workplace_private\mongoDBTest\helloMongoose> node .\helloDocument.js
数据库连接成功~~~
(node:66616) [MONGODB DRIVER] Warning: collection.update is deprecated. Use updateOne, updateMany, or bulkWrite instead.
修改成功~~~
*/
  • 也可以使用以下方法修改
StuModel.findOne({}, function(err, doc){
  if(!err){
    doc.age = 20;
    doc.save();
  }
});

删除

  • 删除查询到的数据
StuModel.findOne({}, function(err, doc){
  if(!err){
    doc.remove(function(err){
      if(!err){
        console.log("删除成功~~~");
      }
    })
  }
});

其他方法/属性

  • get(name):获取文档中指定属性值
  • set(name, value):设置文档指定属性值
  • id:文档的 _id 属性值
  • toJSON()
  • toObject()

mongoose 模块化

  1. 新建 tools 目录,并在 tools 目录下新建 conn_mongo.js 文件
/**
 * 定义一个模块,连接 MongoDB 数据库
 */
var mongoose = require("mongoose");
mongoose.connect('mongodb://127.0.0.1/mongoose_test');
mongoose.connection.once("open", function(){
  console.log("数据库连接成功~~~");
});
  1. 新建 models 目录,并在 models 下新建 student.js 文件
/**
 * 定义 student 模型
 */
var mongoose = require("mongoose");

var Schema = mongoose.Schema;

var stuSchema = new Schema({
  name: String,
  age: Number,
  gender: {
    type: String,
    default: "female"
  },
  address: String
});

// 定义模型
var StuModel = mongoose.model("student", stuSchema);

module.exports = StuModel;
  1. 在根目录下新建 index.js
require("./tools/conn_mongo");
var Student = require("./models/student");

Student.find({}, function(err, docs){
  if(!err){
    console.log(docs);
  }
});
  1. 运行
**\helloMongoose> node .\index.js
数据库连接成功~~~
[
  {
    _id: new ObjectId("61bc9aef975b266f07bb657e"),
    name: '孙悟空',
    age: 20,
    gender: 'male',
    address: '花果山',
    __v: 0
  },
  {
    _id: new ObjectId("61bd3e1885eebfa86f8a2e03"),
    name: '猪八戒',
    age: 28,
    gender: 'male',
    address: '高老庄',
    __v: 0
  },
  {
    _id: new ObjectId("61bd3e1885eebfa86f8a2e04"),
    name: '唐僧',
    age: 20,
    gender: 'male',
    address: '东土大唐',
    __v: 0
  },
  {
    _id: new ObjectId("61bd3f924545d40f7c4ac800"),
    name: '沙和尚',
    age: 38,
    gender: 'male',
    address: '流沙河',
    __v: 0
  },
  {
    _id: new ObjectId("61bd7a9702aa404c44bf1877"),
    name: '奔波霸',
    age: 40,
    gender: 'male',
    address: '碧波潭',
    __v: 0
  }
]