Mongodb入门

127 阅读9分钟

Mongodb入门

官方文档:mongoosejs.com/

三个概念:数据库、集合、文档

  • 数据库:数据库是一个仓库,再仓库中可以存放集合
  • 集合:集合类似于数组,在集合中可以存放文档
  • 文档:文档数据库中的最小单位,我们存储和操作的内容都是文档

在mongoDB中,数据库和集合都不需要手动创建

在我们创建文档时,如果文档所在的集合或数据库不存在会自动创建数据库和集合

一、安装mongodb

1.下载地址:www.mongodb.org/dl/win32/ (根据系统版本下载)

2.配置环境变量:把D:\program file\MongoDB\Server\4.4\bin添加到环境变量

image-20220512110338299

有内容说明配置成功

image-20220512110543120

3.在C盘根目录创建一个文件夹data,在data中新建文件夹db(默认数据库目录)

image-20220512110849721

4.启动服务

C:\Users\86183>mongod

image-20220512111202747

5.cmd 连接mongo

image-20220512112321066

  • 通过dbpath指定data路径

    --> mongod ---dbpath D:\data\db(示例路径) 默认监听27017

  • 通过--port更换端口

    --> mongod ---dbpath D:\data\db(数据库路径) --port 10086(端口号) // 不超过65535

6.数据库

  • 数据库的服务器

    • 服务器用来保存数据
    • mongod用来启动服务器
  • 数据库的客户端

    • 客户端用来操作服务器,对数据进行增删改查的操作
    • mongo用来启动客户端

二、MongoDB的基本操作

1.基本指令

1.显示当前的所有数据库

  • show dbs
  • show databases

2.进入到指定的数据库中

  • use 数据库名

3.db代表的是当前所处的数据库

  • db

4.显示数据库中所有的集合

  • show collections

2.数据库中的CRUD操作

Ⅰ向数据库中插入文档(自动创建数据库和集合)

当我们向集合中插入文档时,如果没有给文档指定_id属性,则数据库会自动为文档添加 _id(根据时间戳和机器码生成),该属性作为文档的唯一标识

db.<collection>.insert(doc)  
-向集合中插入一个或多个文档
-例子:向test数据库中的stus集合中插入一个新的学生对象{name:"孙悟空",age:18,gender:"男"}
db.stus.insert({name:"孙悟空",age:18,gender:"男"})

image-20220512140700193

db.<collection>.find()
查询集合中的所有文档,,,mongodb会自动生成id

image-20220512141046307

安装图形化界面

免费工具官网:www.mongodbmanager.com/download-mo…

解决无法输入中文问题:

image-20220512144426900

调整字体问题:

image-20220512144702156

插入多个文档

image-20220512145250301

image-20220512145344909

db.collection.insertOne()   // 插入一个文档对象
db.collection.insertMany()   // 插入多个文档对象
// 直接用insert也可以,insertOne和insertMany语义更加清晰
Ⅱ 查询
db.collection.find()   
-find() // 查询集合中所有符合条件的文档
-find() // 可以接收一个对象作为条件参数
db.stus.find({_id:"627ca36fd1fc4d6178d4aa19"})   // 返回的是一个数组

image-20220512151343282

db.collection.findOne()   // 用来查询集合中符合条件的第一个文档,返回的是一个文档对象
查询有几个文档对象,统计数量
db.collection.find({}).count();  
或
db.collection.find({}).length();  
Ⅲ 修改
db.collection.update(查询对象,新对象)     // update默认情况下只改一个
// update()  默认情况下会使用新对象来替换旧对象
db.stus.update({name:"沙和尚"},{age:28})  // 会将{name:"沙和尚"}一整个文档对象都替换成{age:28}        慎用

image-20220512153133041

如果需要修改指定的属性,而不是替换需要使用“修改操作符”来完成修改 $set可以用来修改文档中的指定属性

image-20220512153436965

image-20220512153845681

$unset  删除文档的指定属性

image-20220512154023036

db.collection.updateMany()    // 同时修改多个符合条件的文档
db.collection.updateOne()    // 修改一个符合条件的文档

---------------------------

db.collection.updateOne()
// 等价于
db.collection.update()

--------------------

db.collection.updateMany()
// 等价于
db.collection.update(
	<query>,   // 匹配条件
	<update>,   // 更新结果
	{
		multi: true   // boolean    
	}
)

-------------------------------

db.collection.replaceOne()   // 替换一个文档
Ⅳ 删除
db.collection.remove()     // 删除符合条件的所有文档(默认情况删多个)
db.collection.deleteOne()   // 只可以删一个
db.collection.deleteMany()   // 只可以删多个
// 传递条件的方式和find一样

---------------------

db.collection.remove()
// 等价于
db.collection.deleteMany()

-----------------------

db.collection.deleteOne()
//等价于
db.collection.remove(
	<query>;
	<justone>   // true
)

--------------------------

// remove 如果只传递一个空对象作为参数,则会删除集合中的所有文档
db.collection.remove({})   // 清空集合(性能略差:一个一个删)
---> 直接删集合,当数据库只有这一个集合时,数据库也会被删除
db.collection.drop();

删除数据库
db.dropDatabase()
db.collection.remove({_id:"qwe"});    // 删除_id为qwe的文档
一般情况下不直接删除数据,设置一个属性值,将需要删除的文档把特定属性值设置为1

假设有这些数据

image-20220512163045102

删除lisi,就把李四的isDel改成1

image-20220512163423111

练习一

1.进入my_test数据库
use my_test;

2.向数据库的user集合中插入一个文档
db.user.insert(
    {name:"sunwukong",age:300,sex:"male"}
);

3.查询user集合中的文档
db.user.find();

4.向数据库的user集合中插入一个文档
db.user.insert(
    {name:"tangseng",age:30,sex:"male"}
);

5.查询数据库user集合中的文档
db.user.find();

6.统计数据库user集合中的文档数量
db.user.find().count();

7.查询数据库user集合中的name为sunwukong的文档
db.user.find({name:"sunwukong"});

8.向数据库user集合中的name为sunwukong的文档添加一个address属性,属性值为huaguoshan
db.user.update(
    {name:"sunwukong"},
    {$set:{
        address:"huaguoshan"
    }}
)

9.使用{name:"zhubajie"} 替换username为tangseng的文档
db.user.update(
    {name:"tangseng"},
    {$set:{
        name:"zhubajie"
    }}
);

10.删除name为sunwukong的文档的address属性
db.user.update(
    {name:"sunwukong"},
    {$unset:{
        address:"huaguoshan"
    }}
)

11.向name为sunwukong的文档中添加一个hobby:{cities:["beijing","shanghai","shenzhen"],movies:["sanguo","hero"]}
db.user.update(
    {name:"sunwukong"},
    {$set:{
        hobby:{
            cities:["beijing","shanghai","shenzhen"],
            movies:["sangou","hero"]
        }
    }}
)

12.向name为zhubajie的文档中,添加一个hobby:{movies:["A Chinese Odyssey","King of comedy"]}
db.user.update(
    {name:"zhubajie"},
    {$set:{
        hobby:{
            movies:["A Chinese Odyssey","King of comedy"]
        }
    }}
);

13.查询喜欢电影hero的文档
// MongoDB支持直接通过内嵌文档的属性进行查询,如果要查询内嵌文档则可以通过.的形式来匹配
// 如果要通过内嵌文档来对文档进行查询,此时属性名必须使用引号
db.user.find({"hobby.movies":"hero"});

14.向zhubajie中添加一个新的电影Interstellar
// 错误示范:直接把hobby.movies里面的值设置为Interstellar,类型是一个字符串
db.user.update(
    {name:"zhubajie"},
    {$set:{
        "hobby.movies":"Interstellar"   
    }}
);
// 正确写法:   $push用于向数组添加一个新的元素  不会考虑元素是否重复
// $addToSet  向数组中添加一个新元素 会考虑元素是否存在,如果已经存在该元素,则不会添加
db.user.update(
    {name:"zhubajie"},
    {$push:{
        "hobby.movies":"Interstellar"   
    }}
);


15.删除喜欢beijing的用户
db.user.remove(
    {"hobby.cities":"beijing"}
);

16.删除user集合
db.user.remove({});
db.user.drop();

17.向numbers中插入20000条数据
for(var i=1;i<=20000;i++){   // 用时 10.2s   效率太低
    db.numbers.insert({num:i});
}

// 高性能:0.3s
var arr = [];
for(var i=1;i<=20000;i++){
    arr.push({num:i});
}
db.numbers.insert(arr);


18.查询numbers中num为500的文档
db.numbers.find({num:500});
或:db.numbers.find({num:{$eq:5000}});

19.查询numbers中num大于5000的文档
db.numbers.find({num:{$gt:5000}});

20.查询numbers中num小于30的文档
db.numbers.find({num:{$lt:30}});

21.查询numbers中num大于40小于50的文档
db.numbers.find({num:{$gt:40 , $lt:50}});

22.查询numbers中num大于19996的文档
db.numbers.find({num:{$gt:19996}});

23.查看numbers集合中的前10条数据
db.numbers.find({num:{$lt:10}});   // 有序
// limit设置显示数据的上线
db.numbers.find().limit(10);
// 在开发时,绝对不会执行不带条件的查询

24.查看numbers集合中的第11条到第20条数据
// skip()用于跳过指定数量的数据
//skip((页码-1)*每页显示的条数).limit(每页显示的条数)
// skip()和limit()的先后顺序可以变换,mongoDB会自动调整顺序
db.numbers.find().skip(10).limit(10);

25.查看numbers集合中的第21条到第30条数据
db.numbers.find().skip(20).limit(10);

三、文档间的关系

  • 一对一 (one to one)【举例:夫妻】

    • 在MongoDB,可以通过内嵌文档的形式体现出一对一的关系
    • db.wifeAndhusband.insert(
          {name:"黄蓉",husband:{name:"郭靖"}},
          {name:"潘金莲",husband:{name:"武大郎"}}
      );
      
  • 一对多 (one to many) / 多对一 (many to one) 【父母-孩子】【用户-订单】

  • 也可以通过内嵌文档来映射一对多的关系

    // 创建两个用户
    db.users.insert([
        {username:"swk"},
        {username:"zbj"}
    ]);
    // 通过绑定id可知这个订单是该用户的
    db.orders.insert({
        list:["苹果","香蕉","大鸭梨"],
        user_id:ObjectId("627dbcef816c103eb9437dfb")
    });
    // 一个用户可以有多个订单
    db.orders.insert({
        list:["嘻哈裤","杰克衫"],
        user_id:ObjectId("627dbcef816c103eb9437dfb")
    });
    db.orders.insert({
        list:["猪肉","鸭肉","漫画"],
        user_id:ObjectId("627dbcef816c103eb9437dfc")
    });
    
    // 查找某个用户的订单
    var user_id = db.users.findOne({username:"swk"})._id;
    db.orders.find({user_id:user_id})
    
  • 多对多 (many to many) 【分类--商品】 【老师--学生】

    // 老师--学生     
    db.teachers.insert([    {name: "洪七公"},    {name: "黄药师"},    {name: "龟仙人"}]);
    // 一个学生对应多个老师
    db.stus.update(
        {name:"zhangsan"},
        {$set:{tech_ids:[
            ObjectId("627dc1f4816c103eb9437e00"),
            ObjectId("627dc1f4816c103eb9437e01")
        ]}}
    );
    // 一个老师对应多个学生
    db.teachers.update(
        {name:"洪七公"},
        {$set:{stu_ids:[
            ObjectId("627cc3692526994e5ad1b3f5"),
            ObjectId("627cc3692526994e5ad1b3f6"),
            ObjectId("627cc3692526994e5ad1b3f7")
        ]}}
    );
    

练习二

26.将dept和emp集合导入到数据库中

27.查询工资小于2000的员工
db.emp.find({sal:{$lt:2000}});

28.查询工资在1000-2000之间的员工
db.emp.find({sal:{$lt:2000,$gt:1000}});

29.查询工资小于1000或大于2500的员工
db.emp.find({
    $or:[
    	{sal:
    		{$lt:2000}
    	},
    	{sal:
    		{$gt:1000}
    	}
    ]
});

30.查询财务部(depno)的所有员工
var deptno = db.dept.findOne({dname:"财务部"}).deptno;
db.emp.find({depno:depno})

31.查询销售部的所有员工
var deptno = db.dept.findOne({dname:"销售部"}).deptno;
db.emp.find({depno:depno})

32.查询所有mgr为7698的所有员工
db.emp.find({mgr:7698});   // 注意数据类型

33.为所有薪资低于1000的员工增加工资400// $inc 在原来的基础上进行增加
db.emp.updateMany({sal:{$lte:1000}},{$inc:{sal:400}});

四、sort和投影

Ⅰsort

查询文档时,默认情况是按照_id的值进行排序(升序)

sort()可以用来指定文件的排序规则,sort()需要传递一个对象来指定排序规则,1表示升序,-1表示降序

db.emp.find({}).sort({sal:1,empno:-1})   // 先按照工资升序排序,工资相同的编号按照降序排序

limit skip sort 可以以任意顺序进行进行调用

Ⅱ 投影

// 在查询时,可以在第二个参数的位置来设置查询结果的投影
db.emp.find({},{ename:1});    // 只显示id(默认显示)和姓名
db.emp.find({},{ename:1,_id:0});    // 只显示姓名

五、Mongoose

让我们可以通过Node来操作MongoDB模块

Mongoose是一个对象文档模型库(ODM)

Mongoose的好处

1.可以为文档创建一个模式结构(Schema),约束文档结构,确保数据是对的

2.可以对模型中的对象/文档进行验证

3.数据可以通过类型转换为对象模型

4.可以使用中间件来应用业务逻辑挂钩

5.比Node原生的MongoDB驱动更容易

Mongoose中为我们提供了几个新的对象

  • Schema(模式对象)

    • Schema对象定义约束了数据库中的文档结构
  • Model

    • Model对象作为集合中的所有文档的表示,相当于MongoDB数据库中的集合collection
  • Document

    • Document表示集合中的具体文档,相当于集合中的一个具体文档

\