安装及配置(mac)
命令行安装
-
cd /usr/local 进入目录
-
sudo curl -O fastdl.mongodb.org/osx/mongodb… 该地址替换为最新版本地址
获取方式:进入 www.mongodb.com/try/downloa… 点击copy link
-
sudo tar -zxvf mongodb-macos-x86_64-5.0.6.tgz 解压
-
sudo mv mongodb-macos-x86_64-5.0.6.tgz/ mongodb 解压后改名,不要忘了改文件名
配置全局变量
-
cd ~
-
vim .bash_profile
在文件中添加
export PATH=${PATH}:/usr/local/mongodb/bin/:wq 保存退出
-
source .bash_profile 刷新终端
-
mongod --version 验证版本号是否成功。
Tip: 开启新的终端验证是否依然成功,若发现无效了,大概是 .zshrc 文件中没有自动执行我们配置的全局变量.
resolve:
- vim .zshrc
- 在文件中添加
source .bash_profile,:wq保存退出 - source .zshrc 刷新终端
启动和停止 mongodb 服务
- 在 /usr/local/mongdb 目录下创建文件夹: data/db/
- 启动 mongodb 服务:
mongod --dbpath /usr/local/mongodb/data/db. control + C或 直接 'x' 掉终端 便可关闭服务。
mongoShell - 连接 mongodb 服务
开启新的终端执行 mongo 或点击mongo shell 直接执行
mongo Shell 执行环境
- 提供了 javascript 执行环境
- 内置了一些数据库操作命令
- show dbs
- db
- use database
- show collections
- ...
- 提供了一大推的内置API用来操作数据库
- db.users.insert({ name: 'jack', age: 18 })
退出连接 三种方式:
- exit
- quit()
- control + C 或直接关闭
基本概念
数据存储结构
由于 mongodb 是文档型数据库,其中存储到数据就是熟悉的 JSON 格式数据。
- 可以把 mongodb 数据库想象成一个超级大的对象
- 对象里面有不同的集合
- 集合中有不同的文档
{
// 数据库 Database
"jingdong": {
// 集合 collection,对应关系型数据库中的 Table
"user": [
// 文档 Document,对应关系型数据库中的 Row
{
// 数据字段 Field,对应关系型数据库总的 Column
"id": 1,
"username": "zhangsan",
"password": "123"
},
{
"id": 2,
"username": "lisi",
"password": "123"
}
],
"products": [
{
"id": 1,
"username": "wangwu",
"password": "123"
},
{
"id": 2,
"username": "lisi",
"password": "123"
}
]
},
// 数据库 Database
"tianmao": {}
}
数据库
在 mongodb 中,数据库包含一个或多个文档集合。
查看数据库列表
show dbs
查看当前数据库
db
mongodb 中默认的数据库为 test, 如果没有创建新的数据库,集合将存放在 test 数据库中。
有一些数据库名是保留的,可以直接访问这些有特殊作用的数据库。
- admin。 从权限的角度看,这是“root”数据库。如果将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或者关闭数据库。
- local。这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合。
- config。当 mongo 用于分片设置时,config 数据库在内部使用,用于保存分片的相关信息。
切换数据库
use <DATABASE_NAME>
创建数据库
use <DATABASE_NAME>
在 mongodb 中数据库只有真正的有了数据才会被创建出来。所以我们可以切换到不存在的数据库,首次将数据存储到数据库中时(例如通过创建集合),mongodb 会创建数据库。
删除数据库
db.dropDatabase()
集合
集合类似于关系型数据库中的表,mongodb 将文档存储在集合中。
创建集合 如果不存在集合,则在第一次为该集合存储数据时,mongodb 会创建该集合。
db.user.insert({name:'jack'})
mongodb 提供 db.createCollection() 方法来显式创建具有各种选项的集合,例如设置最大大小或文档验证规则。如果未指定这些选项,则无需显式创建集合,因为在首次存储集合数据时,mongodb 会创建新集合。
查看所有集合
show collections
查看集合中所有选项
db.user.find()
user 为集合名称
删除集合
db.user.drop()
user 为集合名称
文档
- mongodb 将数据记录存储为 BSON 文档
- BSON(Binary JSON)是 JSON 文档的二进制表示形式,它比 JSON 包含更多的数据类型
文档结构
mongodb 文档由字段和值对组成,并具有以下结构:
数据类型
字段的值可以是任何 BSON 数据类型,包括其他文档,数组和文档水。例如,一下文档包含各种类型的值:
- _id 保存一个 ObjectId 类型
- name 包含一个嵌入式文档,该文档包含 first 和 last 字段
- birth 和 death 持有 Date 类型的值
- contribs 保存一个字符串数组
- views 拥有 NumberLong 类型的值
mongoShell 基础操作
数据的增删改查,简称 CRUD。
- Create 创建
- Read 读取
- Update 更新
- Delete 删除
mongodb 图形管理软件
为了更好的学习 CRUD 及之后的语法,建议选择一款图形软件更方便操作。
- Robo 3T
- Studio 3T
- Navicat
- MongoDB Compass
- ...
这些工具各有优劣,根据个人喜好选择即可,我推荐 Navicat 这个工具。
创建文档
创建或插入操作将新文档添加到集合中。如果集合当前不存在,则插入操作将创建集合。mongodb 提供以下方法,用于将文档插入集合中:
- db.collection.insertOne(). 插入单个文档到集合中,传入一个对象
- db.collection.insertMany(). 插入多个文档到集合中,传入一个数组
- db.collection.insert(). 插入一个或多个文档到集合中
插入行为
1、 集合创建 如果该集合当前不存在,则插入操作将创建该集合
2、在 mongodb 中,存储在集合中的每个文档都需要一个唯一的 _id 字段作为主键。如果插入的文档省略 _id 字段,则 mongodb 驱动程序会自动为 _id 字段生成 ObjectId.
查询文档
基本查询
- db.collection.find(query, projection)
- query: 可选,使用查询操作符指定查询条件
- projection: 可选,使用投影操作符制定返回的键。查询时返回文档中所有键值,只需省略该参数即可(默认省略)。
- db.collection.findOne()
例如,如果我们先插入数据:
db.inventory.insertMany([
{ item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
{ item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "A" },
{ item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },
{ item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },
{ item: "postcard", qty: 50, size: { h: 10, w: 15.25, uom: "cm" }, status: "B" }
]);
查询所有文档
db.inventory.find()
条件查询
db.inventory.find({status:'A'})
代表查询所有 status 为 A 的。
指定返回的字段
db.inventory.find({},{
item: 1,
status:1
})
item 和 status 为文档中的两个字段,1 代表返回这个字段。
指定 AND 条件
db.inventory.find({status:'A', qty: 50})
指定 OR 条件
db.inventory.find({
$or: [
{status: 'A'},
{qty: 50}
]
})
指定 AND 和 OR 条件
db.inventory.find({
status: "A",
$or: [ { qty: { $lt: 30 } }, { item: /^p/ } ]
})
查询操作符
参考: docs.mongodb.com/manual/refe…
比较运算符:
| 名称 | 描述 |
|---|---|
$eq | 匹配等于指定值的值。 |
$gt | 匹配大于指定值的值。 |
$gte | 匹配大于或等于指定值的值。 |
$in | 匹配数组中指定的任何值。 |
$lt | 匹配小于指定值的值。 |
$lte | 匹配小于或等于指定值的值。 |
$ne | 匹配所有不等于指定值的值。 |
$nin | 不匹配数组中指定的任何值。 |
逻辑运算符:
| 名称 | 描述 |
|---|---|
$and | 将查询子句与逻辑连接,并返回与这两个子句条件匹配的所有文档。 |
$not | 反转查询表达式的效果,并返回与查询表达式不匹配的文档。 |
$nor | 用逻辑NOR连接查询子句,返回所有不能匹配这两个子句的文档。 |
$or | 用逻辑连接查询子句,或返回与任一子句条件匹配的所有文档。 |
例如:查询 qty 大于等于50的
db.inventory.find({
qty:{
$gte: 50
}
})
例如:匹配 status 为 A 或 D 的
db.inventory.find({
status: {$in:["A","D"]}
})
查询嵌套文档
直接匹配整个嵌套文档
注意:匹配嵌套文档时,传入的文档必须和真实文档完全匹配,包括字段的顺序。例如以下改变字段顺序将无法匹配到文档:
查询嵌套字段
相等匹配:
运算符匹配:
指定 AND 条件:
查询数组
练习之前我们先把之前的数据删除,重新插入测试数据:
db.inventory.insertMany([
{ item: "journal", qty: 25, tags: ["blank", "red"], dim_cm: [ 14, 21 ] },
{ item: "notebook", qty: 50, tags: ["red", "blue"], dim_cm: [ 14, 21 ] },
{ item: "paper", qty: 100, tags: ["red", "blank", "plain"], dim_cm: [ 14, 21 ] },
{ item: "planner", qty: 75, tags: ["blank", "red"], dim_cm: [ 22.85, 30 ] },
{ item: "postcard", qty: 45, tags: ["blue"], dim_cm: [ 10, 15.25 ] }
]);
匹配一个数组
db.inventory.find({
tags: ["red", "blank"]
})
匹配数组也会完全匹配,包括元素的顺序。
如果想找到一个同时包含元素“red” 和“blank” 的数组,但不考虑顺序和是否有其他元素,可以使用 $all 运算符:
db.inventory.find({
tags: {$all:["red","blank"]}
})
查询数组中的元素
查询包含 tags 中包含 blue 元素的项:
db.inventory.find({
tags: 'blue'
})
查询 dim_cm 中包含大于25的项
db.inventory.find({
dim_cm: {$gt: 25}
})
为数组指定多个条件
- 使用数组元素上的复合过滤条件查询数组。以下例子,表示查询 dim_cm 数组包含可以满足各自条件的元素。即, dim_cm 包含大于20的元素,也包含小于15的元素。
db.inventory.find({
dim_cm: {$gt: 20, $lt: 15}
})
- 查询满足多个条件的数组元素。使用 $elemMatch 运算符可以在数组的元素上指定多个条件。以下例子,表示查询 dim_cm 数组中包含同时满足大于22且小于30的元素。
db.inventory.find({
dim_cm: { $elemMatch: {$gt: 22, $lt: 30}}
})
- 通过数组索引位置查询元素 查询 dim_cm 数组中索引位置为1时大于25的元素
db.inventory.find({
"dim_cm.1": {$gt: 25}
})
- 通过数组长度查询数组。使用 $size 运算符可按元素数量查询数组。以下例子,表示查询 tags 数组长度为3的。
db.inventory.find({
"tags": {$size: 3}
})
查询嵌套文档中的数组
测试数据:
db.inventory.insertMany( [
{ item: "journal", instock: [ { warehouse: "A", qty: 5 }, { warehouse: "C", qty: 15 } ] },
{ item: "notebook", instock: [ { warehouse: "C", qty: 5 } ] },
{ item: "paper", instock: [ { warehouse: "A", qty: 60 }, { warehouse: "B", qty: 15 } ] },
{ item: "planner", instock: [ { warehouse: "A", qty: 40 }, { warehouse: "B", qty: 5 } ] },
{ item: "postcard", instock: [ { warehouse: "B", qty: 15 }, { warehouse: "C", qty: 35 } ] }
]);
查询嵌套在数组中的文档
db.inventory.find({
instock: { warehouse: "A", qty: 5 }
})
匹配文档需完全匹配。
在文档数组中的字段上指定查询条件
db.inventory.find({
"instock.qty": {$gt: 20}
})
如下图,查询到的是包含 qty 大于 20 的项。
使用数组索引在嵌套文档中查询字段
db.inventory.find({
"instock.0.qty": {$gt: 20}
})
如下图,查询到的是 instock 中第0项 qty 大于20的。
多条件
查询同时满足 qty 为5, warehouse 为 A 的项:
db.inventory.find({
"instock": {$elemMatch: {qty: 5, warehouse:"A"}}
})
查询 instock 中 qty 同时满足大于20 小于等于60 的项。
db.inventory.find({
"instock": {$elemMatch: {qty: {$gt: 20, $lte: 60}}}
})
包含 qty 大于10的,也包含 qty 小于等于20 的:
db.inventory.find({
"instock.qty": {$gt: 10, $lte: 20}
})
包含 qty 为5的,也包含 warehouse 为 A的:
db.inventory.find({
"instock.qty": 5,
"instock.warehouse":"A"
})
指定返回字段
测试数据:
db.inventory.insertMany( [
{ item: "journal", status: "A", size: { h: 14, w: 21, uom: "cm" }, instock: [ { warehouse: "A", qty: 5 } ] },
{ item: "notebook", status: "A", size: { h: 8.5, w: 11, uom: "in" }, instock: [ { warehouse: "C", qty: 5 } ] },
{ item: "paper", status: "D", size: { h: 8.5, w: 11, uom: "in" }, instock: [ { warehouse: "A", qty: 60 } ] },
{ item: "planner", status: "D", size: { h: 22.85, w: 30, uom: "cm" }, instock: [ { warehouse: "A", qty: 40 } ] },
{ item: "postcard", status: "A", size: { h: 10, w: 15.25, uom: "cm" }, instock: [ { warehouse: "B", qty: 15 }, { warehouse: "C", qty: 35 } ] }
]);
仅返回指定字段和 _id 字段
db.inventory.find( { status: "A" }, { item: 1, status: 1 } )
禁止 _id 字段
db.inventory.find( { status: "A" }, { item: 1, status: 1, _id: 0 } )
排除指定字段
db.inventory.find( { status: "A" }, { status: 0, instock: 0 } )
返回/禁止嵌入式文档中的特定字段
db.inventory.find(
{ status: "A" },
{ item: 1, status: 1, "size.uom": 1 }
)
db.inventory.find(
{ status: "A" },
{ item: 1, status: 1, "size": { "uom": 1 } }
)
db.inventory.find(
{ status: "A" },
{ "size.uom": 0 }
)
指定数组的返回
// 数组指定字段
db.inventory.find( { status: "A" }, { item: 1, status: 1, "instock.qty": 1 } )
// 指定返回 instock 的最后一项
// $slice 为正数时,返回前 n 项
// $slice 为负数时,返回后 n 项
db.inventory.find( { status: "A" }, { item: 1, status: 1, instock: { $slice: -1 } } )
查询空字段或缺少字段
测试数据:
db.inventory.insertMany([
{ _id: 1, item: null },
{ _id: 2 }
])
相等过滤器
查询 item 为 null 或不包含 item 的文档。
db.inventory.find( { item: null } )
类型检查
查询 item 仅为 null 的文档。即 item 字段的值为 BSON 类型为 Null(类型编号10):
db.inventory.find( { item : { $type: 10 } } )
存在检查
db.inventory.find( { item : { $exists: false } } )
更新文档
db.collection.updateOne(<filter>,<update>,<optioins>)db.collection.updateMany(<filter>,<update>,<optioins>)db.collection.replaceOne(<filter>,<update>,<optioins>)
测试数据:
db.inventory.insertMany( [
{ item: "canvas", qty: 100, size: { h: 28, w: 35.5, uom: "cm" }, status: "A" },
{ item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
{ item: "mat", qty: 85, size: { h: 27.9, w: 35.5, uom: "cm" }, status: "A" },
{ item: "mousepad", qty: 25, size: { h: 19, w: 22.85, uom: "cm" }, status: "P" },
{ item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "P" },
{ item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },
{ item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },
{ item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" },
{ item: "sketchbook", qty: 80, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
{ item: "sketch pad", qty: 95, size: { h: 22.85, w: 30.5, uom: "cm" }, status: "A" }
] );
mongodb 提供了更新操作符(例如 $set)来修改字段值。如果字段不存在,则 $set 将创建该字段。
更新单个文档
db.inventory.updateOne(
{item:'paper'},
{
$set: {"size.uom": "cm", status:"P"},
$currentDate: { lastModified: true }
}
)
更新操作:
- 使用 $set 运算符将 size.uom 值改为 cm, 将 status 值改为 P
- 使用 $currentDate 运算符将 lastModified 字段的值更新为当前日期,如果字段不存在则创建。
更新多个文档
db.inventory.updateMany(
{ "qty": { $lt: 50 } },
{
$set: { "size.uom": "in", status: "P" },
$currentDate: { lastModified: true }
}
)
修改 qty 小于50的所有项。
替换文档
将一个全新的文档作为第二个参数传入,可以修改除 _id 以外的所有文档内容。
db.inventory.replaceOne(
{ item: "paper" },
{ item: "paper", instock: [ { warehouse: "A", qty: 60 }, { warehouse: "B", qty: 40 } ] }
)
删除文档
- db.collection.deleteMany()
- db.collection.deleteOne()
删除所有
db.inventory.deleteMany({})
删除所有符合条件的文档
db.inventory.deleteMany({status:"A"})
仅删除一个符合条件的文档
db.inventory.deleteOne({status:"A"})
在 Node 中操作 MongoDB
mkdir mongodb-demo
cd mongodb-demo
npm init -y
npm i mongodb
启动 mongodb,并插入数据
use myProject
db.users.insertMany([ {name:'jack', age:15}, {name:'zhangsan', age:20}, {name:'lisi', age:18},])
连接 mongodb
在 mongodb-demo 中新建文件 index.js
const { MongoClient } = require('mongodb')
const url = 'mongodb://localhost:27017'
const client = new MongoClient(url);
// database name
const dbName = 'myProject'
async function run() {
try {
await client.connect();
console.log('connect successful')
// 连接数据库
const db = client.db(dbName);
// 连接集合
const collection = db.collection('users');
const users = await collection.find()
console.log(await users.toArray())
} catch (err) {
console.log('connect fail')
} finally {
await client.close()
}
}
run()
CRUD
mongodb 在 nodejs 中的增删改查和 mongdoShell 操作语法是一样的。
- collection.insertMany()
- collection.insertOne()
- collection.find()
- collection.findOne()
- collection.updateMany()
- collection.updateOne()
- collection.replaceOne()
- collection.deleteMany()
- collection.deleteOne()
mongoose 的简单使用
安装:
npm install mongoose
连接数据库:
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() {
// we're connected!
});
定义一个 schema(作为 collection 的 type 定义):
var kittySchema = mongoose.Schema({
name: String
});
定义一个 Kitten 模块(模块相当于 collection):
var Kitten = mongoose.model('Kitten', kittySchema);
创建一个模块的实例就相当于定义了一个文档:
var felyne = new Kitten({ name: 'Felyne' });
console.log(felyne.name); // 'Felyne'
模块可以定义方法,此时的方法在模块的原型链上,每一个实例都可以调用:
kittySchema.methods.speak = function () {
var greeting = this.name
? "Meow name is " + this.name
: "I don't have a name";
console.log(greeting);
}
var Kitten = mongoose.model('Kitten', kittySchema);
var fluffy = new Kitten({ name: 'fluffy' });
fluffy.speak(); // "Meow name is fluffy"
save 方法便可以保存这条文档数据:
fluffy.save(function (err, fluffy) {
if (err) return console.error(err);
fluffy.speak();
});
fluffy.save().then();
通过模块(collection)的 find 方法便可以查询所有文档:
Kitten.find(function (err, kittens) {
if (err) return console.error(err);
console.log(kittens);
})
Kitten.find.then()
更新:
Kitten.findOneAndUpdate(
{}, // 查询条件
{} // 更新数据
).then()
删除
Kitten.findOneAndDelete(
{} // 条件
).then()