title: MongoDB 笔记
date: 2023-02-03 11:13:35
tags:
- MongoDB
1、MongoDB 相关概念
库 <DataBase>
mongodb中的库就类似于传统关系型数据库中库的概念,用来通过不同库隔离不同应用数据。
mongodb中可以建立多个数据库。每一个库都有自己的集合和权限,不同的数据库也放置在不同的文件中。默认的数据库为"test",数据库存储在启动指定的data目录中。
集合 <collection>
集合就是 MongoDB文档组,类似于RDBMS(关系数据库管理系统: RelationalDatabase Management System)中的表的概念。
集合存在于数据库中,一个库中可以创建多个集合。每个集合没有固定的结构,这意味着你在对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。
文档 <Document>
文档集合中一条条记录,是一组键值(key-value)对(即BSON)。MongoDB的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是MongoDB非常突出的特点。
2、库的相关操作
查看所有库
> show databases; | show dbs
admin
:从权限的角度来看,这是"root"数据库。要是将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或者关闭服务器。local
:这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合config
:当Mongo用于分片设置时, config数据库在内部使用,用于保存分片的相关信息。
创建数据库
> use 库名
删除数据库
- 默认删除当前选中的库
> db.dropDatabase()
查看当前所在库
> db;
3、集合的相关操作
查看库中所有集合
> show collections; | show tables;
创建集合
> db.createCollection('集合名称', [options])
options 可以是如下参数:
字段 | 类型 | 描述 |
---|---|---|
capped | 布尔 | (可选)如果为true,则创建固定集合。固定集合是指有着固定大小布尔的集合,当达到最大值时,它会自动覆盖最早的文档。当该值为true时,必须指定size参数。 |
size | 数值 | (可选)为固定集合指定一个最大值,即字节数。如果capped为true,也需要指定该字段。 |
max | 数值 | (可选)指定固定集合中包含文档的最大数量。 |
注意:当集合不存在时,向集合插入该文档也会自动创建该集合。
4、文档
插入
插入文档
-
多条文档
> db.集合.insert({ username: "sunwukong" });
-
多条文档
> db.集合名称.insertMany( [<document 1>, <document 2>], { writeConcern: 1, // 写入策略,默认为1,即要求确认写作,0是不要求 ordered: true // 指定是否按顺序写入,默认true,按顺序写入 } ) > db.集合.insert([ {username: "金俊菀"}, {username: "安正源"}, ])
-
脚本方式
for (int i = 0; i < 100; i ++ ) { db.users.insert({"_id": i, "name": "yisheng_" + i, "age": 23}) }
删除文档
删除文档
db.colection.remove(
<query>,
{
justOne: <boolean>,
writeConcern: <document>
}
)
参数说明:
query
:可选删除的文档的条件。justOne
:可选如果设为true或1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。writeConcern
:可选抛出异常的级别。
更新文档
更新文档
db.colection.update(
<query>,
{
justOne: <boolean>,
writeConcern: <document>
}
)
参数说明:
query
:update的查询条件,类似sql update查询内where后面的。update
: update的对象和一些更新的操作符(如$
,$inc
...)等,也可以理解为sql update查询内set后面的upsert
:可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。multi
:可选,mongodb默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。writeConcern
:可选,抛出异常的级别。
- db.集合名称.update( {" name" : "zhangsan" } , {name : "11" , bir:new date()})`
这个更新是将符合条件的全部更新成后面的文档,相当于先删除在更新`
- db.集合名称.update( { " name" : "xiaohei" } ,{$set: {name : "mingming"}})
保留原来数据更新,但是只更新符合条件的第一条数据
- db.集合名称.update( {name :"小黑"},{$set: {name: "小明"}},{multi:true})
保留原来数据更新,更新符合条件的所有数据
- db.集合名称.update( {name :"小黑"},{$set : {name : "小明”}},{multi:true, upsert:true })
保留原来数据更新,更新符合条件的所有数据没有条件符合时插入数据
查询文档
查询所有
> db.集合名称.find(query, projection)
- query∶可选,使用查询操作符指定查询条件
- projection:可选,使用投影操作符指定返回的键。查询时返回文档中所有键值,只需省略该参数即可(默认省略)。
如果需要以易读的方式来读取数据,可以使用pretty()方法,语法格式如下:
> db.集合名称.find().pretty()
MongoDB 与 RDBMS Where 语句比较
AND 条件
MongoDB 的 find() 方法可以传入多个键(key),每个键(key)以逗号隔开,即常规 SQL 的 AND 条件。
语法格式如下:
> db.collection.find({key1:value1, key2:value2}).pretty()
e.g.: WHERE by='菜鸟教程' AND title='MongoDB 教程'
> db.collection.find({"by": "菜鸟教程", "title": "MongoDB 教程"}).pretty()
OR 条件
MongoDB OR 条件语句使用了关键字 $or,语法格式如下:
> db.col.find(
{
$or: [
{key1: value1}, {key2:value2}
]
}
).pretty()
e.g. : by 值为 菜鸟教程 或键 title 值为 MongoDB 教程
> db.col.find({
$or: [
{"by": "菜鸟教程"},
{"title": "MongoDB 教程"}
]
}).pretty()
AND 和 OR 联合使用
e.g: 类似常规 SQL 语句为: 'where likes>50 AND (by = '菜鸟教程' OR title = 'MongoDB 教程')'
db.col.find({
"likes": {$gt: 50},
$or: [
{"by": "菜鸟教程"},
{"title": "MongoDB 教程"}
]
}).pretty()
模糊查询
类似SQL中 where name like '%name%'
> db.col.find({likes: /良/})
注意:在mongoDB中使用 正则表达式 可以实现近似模糊查询功能
排序
> db.集合名称.find().sort({name : 1 ,age:1})
1 升序 -1 降序
类似SQL中 order by name, age
分页
> db.集合名称.find().sort({条件}).skip(start).limit(rows)
类似SQL中 limit start, rows
总条数
> db.集合名称.count();
> db.集合名称.find({"name": "小张"}).count();
类似SQL中 select count(id) from ...
去重
> db.集合名称.dinstinct('字段')
指定返回名称
> db.集合名称.find({条件}, {name: 1, age: 1})
1 返回 0 不返回 注意:1和0不能同时使用
$type
$type
操作符是基于BSON类型来检索集合中匹配的数据类型,并返回结果。
MongoDB 中可以使用的类型如下表所示:
e.g.
> db.col.insert({
title: 'PHP 教程',
description: 'PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。',
by: '菜鸟教程',
url: 'http://www.runoob.com',
tags: ['php'],
likes: 200
})
>db.col.insert({title: 'Java 教程',
description: 'Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言。',
by: '菜鸟教程',
url: 'http://www.runoob.com',
tags: ['java'],
likes: 150
})
> db.col.insert({title: 'MongoDB 教程',
description: 'MongoDB 是一个 Nosql 数据库',
by: '菜鸟教程',
url: 'http://www.runoob.com',
tags: ['mongodb'],
likes: 100
})
如果想获取 "col" 集合中 title 为 String 的数据,可以使用以下命令:
> db.col.find({"title": {$type: 2}}) // 参考上述表格中的类型对应的数字
或
> db.col.find({"title": {$type: 'string'}})
索引
索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构。
操作
创建索引
> db.集合名称.createIndex(keys, options)
> db.集合名称.createIndex({"title": 1, "description": -1})
说明:语法中Key值为你要创建的索引字段,1为指定按升序创建索引,如果你想按降序来创建索引指定为-1即可。
createIndex() 接收可选参数:
Parameter | Type | Description |
---|---|---|
background |
Boolean | 建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加"background"可选参数。"background”默认值为false。 |
unique |
Boolean | 建立的索引是否唯一。指定为true创建唯一索引。默认值为false. |
name |
string | 索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。 |
expireAfterSeconds |
integer | 指定一个以秒为单位的数值,完成TTL设定,设定集合的生存时间。 |
1、查看集合索引
> db.集合名称.getIndexes()
2、查看集合索引大小
> db.集合名称.totalIndexSize()
3、删除集合所有索引
> db.集合名称.dropIndexes()
4、删除集合指定索引
> db.集合名称.dropIndex()
复合索引
说明:一个索引的值是由多个key进行维护的索引 称之为复合索引
> db.集合名称.createIndex({"title": 1, "description": -1})
注意:mongoDB中复合索引 和 传统关系型数据库一致,都是左前缀原则(B+树)
聚合 aggregate() 方法
MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。有点类似 SQL语句中的 count(*)
。
MongoDB中聚合的方法使用aggregate()。
aggregate() 方法的基本语法格式如下所示:
> db.集合名称.aggregate(AGGREGATE_OPERATION)
eg:集合中的数据如下:
{
_id: ObjectId(7df78ad8902c)
title: 'MongoDB Overview',
description: 'MongoDB is no sql database',
by_user: 'runoob.com',
url: 'http://www.runoob.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
},
{
_id: ObjectId(7df78ad8902d)
title: 'NoSQL Overview',
description: 'No sql database is very fast',
by_user: 'runoob.com',
url: 'http://www.runoob.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 10
},
{
_id: ObjectId(7df78ad8902e)
title: 'Neo4j Overview',
description: 'Neo4j is no sql database',
by_user: 'Neo4j',
url: 'http://www.neo4j.com',
tags: ['neo4j', 'database', 'NoSQL'],
likes: 750
},
现在我们通过以上集合计算每个作者所写的文章数,使用aggregate()计算结果如下:
> db.col.aggregate([{$group: {_id: {"by_user"}, num_tutorial: {$sum: 1}} }])
以上实例类似sql语句:
> select by_user, count(*) from mycol group by by_user
在上面的例子中,我们通过字段 by_user 字段对数据进行分组,并计算 by_user 字段相同值的总和。
下表展示了一些聚合的表达式:
5、整合SpringBoot----MongoTemplate
pom.xml
<!--SpringBoot整合MongoDB-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!--MongoDB相关依赖-->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-sync</artifactId>
<version>3.9.1</version>
</dependency>
配置文件:
# mongodb 无密码
spring.data.mongodb.uri=mongodb://localhost:27017/demos
# mongodb 存在密码
#spring.data.mongodb.host =
#spring.data.mongodb.port =
#spring.data.mongodb.database =
#spring.data.mongodb.username =
#spring.data.mongodb.password =
首先使用@Autowired注入MongoTemplate
@Autowired
private MongoTemplate mongoTemplate;
相关注解
@Document
- 修饰范围:用在类上
- 作用:用来映射这个类的一个对象为mongo中一条文档数据。
- 属性:( value . collection )用来指定操作的集合名称
@Id
- 修饰范围:用在成员变量、方法上
- 作用:用来将成员变量的值映射为文档的_id的值.
@Field
- 修饰范围:用在成员变量、方法上
- 作用:用来将成员变量以及值映射为文档中一个key、value对
- 属性:( name, value )用来指定在文档中 key的名称,默认为成员变量名
@Transient
- 修饰范围:用在成员变量、方法上
- 作用:用来指定改成员变量,不参与文档的序列化
创建集合
@Test
public void testCreateCollection() {
boolean exists = mongoTemplate.collectionExists("products");
if(!exists){
mongoTemplate.createCollection("products");
}
}
- 注意:创建集合不能存在,否则会报错
删除集合
@Test
public void testDropCollection() {
mongoTemplate.dropCollection("products");
}
文档操作
添加
User.java
@Document(value = "users")
public class User {
@Id
private Integer id;
@Field("username")
private String name;
@Field
private Double salary;
@Field
private Date birthday;
// 构造方法等我省略了。。。
}
insert
@Test
public void test() {
User user = new User(2, "小张", 2300.0, new Date());
// 保存对象到mongodb
mongoTemplate.insert(user);
mongoTemplate.save(user);
}
- insert:插入重复数据时,
insert
报DuplicateKeyException
提示主键重复;save
对已存在的数据进行更新。 - save:批处理操作时,
insert
可以一次性插入整个数据,效率较高;save
需要便利整个数据,一次插入或更新,效率极低。
查询
@Test
public void testFind() {
// 1. 查询所有
mongoTemplate.findAll(User.class);
// 2. 基于 id 查询一个
Object byId = mongoTemplate.findById(2, User.class);
System.out.println("基于id查询一个用户:" + byId);
// 3. 条件查询,添加查询 参数1:查询条件 参数2:返回类型
mongoTemplate.find(new Query(), User.class);
// 4. 等值查询
mongoTemplate.find(Query.query(Criteria.where("username").is("小张")), User.class);
// 5. > < >= <= 查询
mongoTemplate.find(Query.query(Criteria.where("salary").lt(2300)), User.class);
// 6. and 查询
mongoTemplate.find(Query.query(Criteria.where("name").is("小张").and("salary").is(2300.0)), User.class);
// 7. or 查询
Criteria criteria = new Criteria();
criteria.orOperator(
Criteria.where("name").is("小张"),
Criteria.where("name").is("小李"),
Criteria.where("age").lt(20000)
);
mongoTemplate.find(new Query(criteria), User.class);
// 8. and or 连用
Criteria criteria1 = new Criteria().and("age").is(23)
.orOperator(Criteria.where("name").is("小张"),
Criteria.where("name").is("小张"));
mongoTemplate.find(Query.query(criteria1), User.class);
// 9. 排序
Query querySort = new Query();
querySort.with(Sort.by(Sort.Order.asc("salary")));
mongoTemplate.find(querySort, User.class);
// 10. 分页查询
Query querySortPage = new Query();
querySortPage.with(Sort.by(Sort.Order.asc("salary")))
.skip(0).limit(2);
List<User> users = mongoTemplate.find(querySortPage, User.class);
users.forEach(System.out::println);
// 11. 查询总条数
long count = mongoTemplate.count(new Query(), User.class);
long count1 = mongoTemplate.count(Query.query(Criteria.where("name").is("小张")), User.class);
System.out.println(count + ", " count1);
// 12. 去重
// 参数1:查询条件 参数2:去重字段 参数3:操作集合 参数4:返回类型
List<String> stringList = mongoTemplate.findDistinct(new Query(), "name", User.class, String.class);
stringList.forEach(System.out::println);
// 13. 使用json字符串方式查询
BasicQuery basicQuery = new BasicQuery("{name: '小张', age: 18}");
BasicQuery basicQuery1 = new BasicQuery("{$or:[{name: '小张'}, {name: '小李'}]}", "{name: 1, age: 1}");
mongoTemplate.find(basicQuery, User.class);
}
更新
@Test
public void testUpdate() {
// 1. 更新条件
Query query = Query.query(Criteria.where("name").is("小张"));
// 2. 更新内容
Update update = new Update();
update.setOnInsert("id", 5);
update.set("salary", 5000);
// 单条更新
mongoTemplate.updateFirst(query, update, User.class);
// 多条更新
mongoTemplate.updateMulti(query, update, User.class);
// 更新插入
UpdateResult updateResult = mongoTemplate.upsert(query, update, User.class);
// 获取本次修改记录
System.out.println(updateResult.getModifiedCount());
// 获取本次匹配的记录
System.out.println(updateResult.getMatchedCount());
// 拿到插入时生成的id,upsertid
System.out.println(updateResult.getUpsertedId());
}
删除
@Test
public void testRemove() {
// 删除所有
mongoTemplate.remove(new Query(), User.class);
// 条件删除
mongoTemplate.remove(Query.query(Criteria.where("name").is("小张")), User.class);
}
标签:name,MongoDB,db,笔记,索引,文档,集合
From: https://www.cnblogs.com/stdxiaozhang/p/17102968.html