● MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的,它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。
● MongoDB的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现了类似关系数据库单表查询的绝大部分功能(可以通过聚合的方式实现多表查询),而且还支持对数据建立索引。
MongoDB基本操作
1基本操作
1.1、数据库以及表的操作
#查看所有的数据库
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
#通过use关键字切换数据库
> use admin
switched to db admin
#创建数据库
#说明:在MongoDB中,数据库是自动创建的,通过use切换到新数据库中,进行插入数据即可自动创建数据库
> use testdb
switched to db testdb
> show dbs #并没有创建数据库
admin 0.000GB
config 0.000GB
local 0.000GB
> db.user.insert({id:1,name:'zhangsan'}) #插入数据
WriteResult({ "nInserted" : 1 })
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
testdb 0.000GB #数据库自动创建
#查看表
> show tables
user
> show collections
user
>
#删除集合(表)
> db.user.drop()
true #如果成功删除选定集合,则 drop() 方法返回 true,否则返回 false。
#删除数据库
> use testdb #先切换到要删除的数据库中
switched to db testdb
> db.dropDatabase() #删除数据库
{ "dropped" : "testdb", "ok" : 1 }
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
1.2、新增数据
在MongoDB中,存储的文档结构是一种类似于json的结构,称之为bson(全称为:Binary JSON)。
#插入数据
#语法:db.COLLECTION_NAME.insert(document)
> db.user.insert({id:1,username:'zhangsan',age:20})
WriteResult({ "nInserted" : 1 })
> db.user.save({id:2,username:'lisi',age:25})
WriteResult({ "nInserted" : 1 })
> db.user.find() #查询数据
{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "id" : 1, "username" : "zhangsan", "age" : 20 }
{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi", "age" : 25 }
● _id 是集合中文档的主键,用于区分文档(记录),_id自动编入索引。
● 默认情况下,_id 字段的类型为 ObjectID,是 MongoDB 的 BSON 类型之一,如果需要,用户还可以将 _id 覆盖为 ObjectID 以外的其他内容。
● ObjectID 长度为 12 字节,由几个 2-4 字节的链组成。每个链代表并指定文档身份的具体内容。以下的值构成了完整的 12 字节组合:
○ 一个 4 字节的值,表示自 Unix 纪元以来的秒数
○ 一个 3 字节的机器标识符
○ 一个 2 字节的进程 ID
○ 一个 3字节的计数器,以随机值开始
1.3、更新数据
update() 方法用于更新已存在的文档。语法格式如下:
db.collection.update(
,
,
[
upsert: ,
multi: ,
writeConcern:
]
)
参数说明:
● query : update的查询条件,类似sql update查询内where后面的。
● update : update的对象和一些更新的操作符(如$,$inc...)等,也可以理解为sql update查询内set后面的
● upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
● multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
● writeConcern :可选,抛出异常的级别。
> db.user.find()
{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "id" : 1, "username" : "zhangsan", "age" : 20 }
{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi", "age" : 25 }
> db.user.update({id:1},{$set:{age:22}}) #更新数据
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find()
{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "id" : 1, "username" : "zhangsan", "age" : 22 }
{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi", "age" : 25 }
#注意:如果这样写,会删除掉其他的字段
> db.user.update({id:1},{age:25})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find()
{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "age" : 25 }
{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi", "age" : 25 }
#更新不存在的字段,会新增字段
> db.user.update({id:2},{$set:{sex:1}}) #更新数据
> db.user.find()
{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "age" : 25 }
{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi", "age" : 25, "sex" : 1 }
#更新不存在的数据,默认不会新增数据
> db.user.update({id:3},{$set:{sex:1}})
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })
> db.user.find()
{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "age" : 25 }
{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi", "age" : 25, "sex" : 1 }
#如果设置第一个参数为true,就是新增数据
> db.user.update({id:3},{$set:{sex:1}},true)
WriteResult({
"nMatched" : 0,
"nUpserted" : 1,
"nModified" : 0,
"_id" : ObjectId("5c08cb281418d073246bc642")
})
> db.user.find()
{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "age" : 25 }
{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi", "age" : 25, "sex" : 1 }
{ "_id" : ObjectId("5c08cb281418d073246bc642"), "id" : 3, "sex" : 1 }
1.4、删除数据
通过remove()方法进行删除数据,语法如下:
db.collection.remove(
,
{
justOne: ,
writeConcern:
}
)
参数说明:
● query :(可选)删除的文档的条件。
● justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。
● writeConcern :(可选)抛出异常的级别。
> db.user.remove({age:25})
WriteResult({ "nRemoved" : 2 }) #删除了2条数据
#插入4条测试数据
db.user.insert({id:1,username:'zhangsan',age:20})
db.user.insert({id:2,username:'lisi',age:21})
db.user.insert({id:3,username:'wangwu',age:22})
db.user.insert({id:4,username:'zhaoliu',age:22})
> db.user.remove({age:22},true)
WriteResult({ "nRemoved" : 1 }) #删除了1条数据
#删除所有数据
> db.user.remove({})
#说明:为了简化操作,官方推荐使用deleteOne()与deleteMany()进行删除数据操作。
db.user.deleteOne({id:1})
db.user.deleteMany({}) #删除所有数据
1.5、查询数据
MongoDB 查询数据的语法格式为:db.user.find([query],[fields])
● query :可选,使用查询操作符指定查询条件
● fields :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)。
如果你需要以易读的方式来读取数据,可以使用 pretty() 方法,语法格式为:db.col.find().pretty()
条件查询:
操作 格式 范例 RDBMS中的类似语句
等于 {:} db.col.find({"by":"xiaojiu"}).pretty() where by = 'xiaojiu'
小于 {:{$lt:}} db.col.find({"likes":{$lt:50}}).pretty() where likes < 50
小于或等于 {:{$lte:}} db.col.find({"likes":{$lte:50}}).pretty() where likes <= 50
大于 {:{$gt:}} db.col.find({"likes":{$gt:50}}).pretty() where likes > 50
大于或等于 {:{$gte:}} db.col.find({"likes":{$gte:50}}).pretty() where likes >= 50
不等于 {:{$ne:}} db.col.find({"likes":{$ne:50}}).pretty() where likes != 50
#插入测试数据
db.user.insert({id:1,username:'zhangsan',age:20})
db.user.insert({id:2,username:'lisi',age:21})
db.user.insert({id:3,username:'wangwu',age:22})
db.user.insert({id:4,username:'zhaoliu',age:22})
db.user.find() #查询全部数据
db.user.find({},{id:1,username:1}) #只查询id与username字段
db.user.find().count() #查询数据条数
db.user.find({id:1}) #查询id为1的数据
db.user.find({age:{$lte:21}}) #查询小于等于21的数据
db.user.find({age:{$lte:21}, id:{$gte:2}}) #and查询,age小于等于21并且id大于等于2
db.user.find({$or:[{id:1},{id:2}]}) #查询id=1 or id=2
#分页查询:Skip()跳过几条,limit()查询条数
db.user.find().limit(2).skip(1) #跳过1条数据,查询2条数据
db.user.find().sort({id:-1}) #按照age倒序排序,-1为倒序,1为正序
2、索引
索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。
MongoDB支持的索引类型有:
● 单字段索引(Single Field)
○ 支持所有数据类型中的单个字段索引
● 复合索引(Compound Index)
○ 基于多个字段的索引,创建复合索引时要注意字段顺序与索引方向
● 多键索引(Multikey indexes)
○ 针对属性包含数组数据的情况,MongoDB支持针对数组中每一个element创建索引。
● 全文索引(Text Index)
○ 支持任意属性值为string或string数组元素的索引查询。
○ 注意:一个集合仅支持最多一个Text Index,中文分词不理想,推荐Elasticsearch。
● 地理空间索引(Geospatial Index)
○ 2dsphere索引,用于存储和查找球面上的点
○ 2d索引,用于存储和查找平面上的点
● 哈希索引(Hashed Index)
○ 针对属性的哈希值进行索引查询,当要使用Hashed index时,MongoDB能够自动的计算hash值,无需程序计算hash值。
○ hash index仅支持等于查询,不支持范围查询。
我们重点需要掌握的是【单字段索引】、【2dsphere索引】。
2.1、单字段索引
#单字段索引,1表示升序创建索引,-1表示降序创建索引
db.集合名.createIndex({"字段名":排序方式})
#示例,创建user集合,其中username字段设置索引
db.user.createIndex({"username":1})
db.user.insert({id:1,username:'zhangsan',age:20})
db.user.insert({id:2,username:'lisi',age:22})
#查看索引
db.user.getIndexes()
#查看索引大小,单位:字节
db.user.totalIndexSize()
#删除索引
db.user.dropIndex("username_1")
#或者,删除除了_id之外的索引
db.user.dropIndexes()
2.2、地理空间索引
MongoDB地理空间索引类型有:
● Point(坐标点),coordinates必须是单个位置
● MultiPoint(多个点),coordinates必须是位置数组
● LineString(线形),coordinates必须是两个或多个位置的数组
● MultiLineString(多行线形),coordinates必须是LineString坐标数组的数组
● Polygon(多边形),coordinates成员必须是 LinearRing 坐标数组的数组,必须是闭环,也就是第一个和最后一个坐标点要相同。
● MultiPolygon(多个多边形),coordinates成员必须是 Polygon 坐标数组的数组。
● GeometryCollection(几何集合),geometries是任何一个对象的集合。
#2dsphere索引
db.集合名.createIndex({"字段名":"2dsphere"})
#示例,创建user集合,其中loc字段设置索引
db.user.createIndex({"loc":"2dsphere"})
db.user.insert({id:3,username:'wangwu',age:21,loc:{type:"Point",coordinates:[116.343847,40.060539]}})
db.user.insert({id:4,username:'zhaoliu',age:23,loc:{type:"Point",coordinates:[121.612112,31.034633]}})
#多边形索引类型示例
#为scpoe集合中的scpoe字段设置球面索引
db.scope.createIndex({"scpoe":"2dsphere"})
#为了便于理解,这里采用x、y坐标系的值来模拟快递员的作业范围
#coordinates格式必须是:[ [ [x,y],[x,y],[x,y] ] ]
db.scope.insert({
id: 1,
username: 'shkdy',
scpoe: {
type: "Polygon",
coordinates: [
[
[0,0],
[3,0],
[3,3],
[0,3],
[0,0]
]
]
}
})
db.scope.insert({
id: 2,
username: 'bjkdy',
scpoe: {
type: "Polygon",
coordinates: [
[
[- 3, 3],
[3, 3],
[3, - 3],
[- 3, - 3],
[- 3, 3]
]
]
}
})
#假设,现在有坐标点[-1,-1]用户下单,就需要查询到所在服务范围内的快递员
#$geoIntersects 查询与指定的几何图形(这里用的是点)相交的数据
#$geometry 指定几何图形
db.scope.find({
scpoe: {
$geoIntersects: {
$geometry: {
type: "Point",
coordinates: [-1, -1]
}
}
}
})
#显然,只能查询到【bjkdy】
#如何坐标点改为[1,1],就可以查询到这两个快递员
db.scope.find({
scpoe: {
$geoIntersects: {
$geometry: {
type: "Point",
coordinates: [1, 1]
}
}
}
})
3.结合Spring的操作
3.1引入依赖
org.springframework.boot
spring-boot-starter-data-mongodb
3.2.配置连接信息
spring:
application:
name: sl-express-mongodb
data:
mongodb:
host: 192.168.150.101
port: 27017
database: sl
authentication-database: admin #认证数据库
username: sl
password: "123321"
auto-index-creation: true #自动创建索引
3.3基本操作
package com.sl.service.Impl;
import com.mongodb.client.result.UpdateResult;
import com.sl.mongo.entity.Person;
import com.sl.service.PersonService;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import java.util.List;
/*
* TODO
* @Author xiaojiu
* @Date 2025/4/17 17:41
*/
@Service
public class PersonServiceImpl implements PersonService {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 新增数据
*
* @param person 数据
*/
@Override
public void savePerson(Person person) {
this.mongoTemplate.save(person);
}
/**
* 更新数据
*
* @param person 数据
*/
@Override
public void update(Person person) {
//更新的条件
Query query=Query.query(Criteria.where("id").is(person.getId()));
//更新的数据
Update update=Update.update("name",person.getName())
.set("age",person.getAge())
.set("location",person.getLocation())
.set("address",person.getAddress());
UpdateResult updateResult = this.mongoTemplate.updateMulti(query, update, Person.class);
System.out.println(updateResult);
System.out.println(updateResult.getModifiedCount());
}
/**
* 根据名字查询用户列表
*
* @param name 用户名字
* @return 用户列表
*/
@Override
public List queryPersonListByName(String name) {
Query query = Query.query(Criteria.where("name").is(name));
return mongoTemplate.find(query, Person.class);
}
/**
* 分页查询用户列表
*
* @param page 页数
* @param pageSize 页面大小
* @return 用户列表
*/
@Override
public List queryPersonPageList(int page, int pageSize) {
//分页条件
PageRequest pageRequest=PageRequest.of(page-1,pageSize, Sort.by(Sort.Order.desc("age")));
//构建查询条件
Query query=new Query().with(pageRequest);
return mongoTemplate.find(query, Person.class);
}
/**
* 根据id删除用户
*
* @param id 主键
*/
@Override
public void deleteById(String id) {
Query query = Query.query(Criteria.where("id").is(new ObjectId(id)));
this.mongoTemplate.remove(query, Person.class);
}
}
Comments NOTHING