Today we will use this blog to understand the architecture of MongoDB, command line operations and using SpringData-MongoDB in JAVA to operate MongoDB.
If you don’t have it installed, you can read this article (59 messages) Open source document database – MongoDB (installation)_Everything will always end up in a boring blog – CSDN blog , install MongoDB.
Let’s take a look at the data characteristics of MongoDB:
- The amount of data storage is large, even massive
- High response speed for data reading and writing
- Data security is not high and there is a certain range of error.
Seeing this, some friends may ask? Oops, let me go, is this MongoDB so awesome?
Then why is it so awesome? Let's take a look at its features.
1. Features
1.1 Data storage
The first feature of MongoDB: data storage
MongoDB uses memory + disk to complete data storage. The interaction between the client and MongoDB is divided into two parts.
The client's operation first operates on the memory. So we know that the operating speed of the memory is the same as the speed of operating the disk, so the memory operation is definitely much faster than the disk operation speed.
So, if your memory is large enough, if I want to query from mengoDB, I can query directly from the memory, avoiding disk query.
Of course, if there is no memory, it will read it from the disk and return it to the client.
The above is about querying, and writing is also written into the memory first, and then returned to the client. Therefore, if you want to write, the memory is directly operated, so its efficiency is extremely high.
Then you may have questions. Now that the data is in the memory, if I restart the server, won't all the data disappear?
In this regard, MongoDB will use the operating system mechanism to automatically map the data in the memory to the disk. However, it will have a time rule and will write every 60 seconds.
Is there any problem with this?
There must be some. If the data has been written into the memory but has not yet been synchronized to the disk, and the power is out, does that mean that the data for the past 60 seconds has been lost? This also explains why MongoDB is more efficient because it operates on memory.
Then there is the problem of data loss in MongoDB? Because it involves data synchronization between memory and disk.
In order to solve this problem, MongoDB optimized the structure in later versions.
It divides the memory into two parts, one is the representative log and the other is the real business data. The same disk is also divided into two parts, one is the log file and the other is the business data file.
When the client sends a request to the memory, it must first record your operation log, and then write it to the memory part of the business data. The memory part of the log will be synchronized with the log part on the disk for 10 milliseconds.
The business data part will be synchronized after 60 seconds.
What are the benefits of this design? First of all, if the server is powered off again, the time it takes to synchronize data between logs is shorter than the previous one. After all, it has been shortened from 60 to 10 milliseconds, so all operation logs will be synchronized to the log file without interruption.
Although the business data may be lost for 60 seconds, it does not matter. The log file will be released. When the server restarts, it will parse the content in the log file and the content of the business data and compare the two.
The lost content is too compensated for storage in files, but no matter how hard mongoDB tries, data will be lost at a certain interval.
1.2 High scalability
The scalability of mongoDB is achieved with the help of built-in data sharding. When we use MongoDB, this often happens. Due to the limited storage capacity of mongoDB's hard disk, redundant data may not be able to be stored.
What should we do at this time? With the built-in data sharding, we can connect multiple mongoDB servers together in series, and each machine stores a part. In this way, the amount of data storage is large.
Using mongDB's built-in data sharding can easily store massive data content, which also lays the foundation for massive data. Although MySQL also supports data sharding, it only needs to use third-party services and components to implement it, and the implementation cost may be higher.
2. Comparison
After reading the above introduction to the characteristics of mengoDB, you may be a little confused. Let me go, redis is already very powerful, and mysql is also very good. Now there is another mongoDB. How should I choose?
- Comparison with Redis
- Redis is a pure memory database. If insufficient memory triggers the elimination strategy, then this part of the content will be really lost!
- Structured storage format (Bson) for easy expansion.
- mongDB can query based on a certain field, but this is not what Redis is good at.
- Compared with MySQL
- MongoDB does not support transactions and multi-table operations; for example, if a user's account needs to satisfy the simultaneous success/failure of multiple operations, then using mongDB is not appropriate.
- MongoDB supports dynamic field management. Example: There are two fields in the data. You save one and it becomes three. When you save four, the number and type of fields can be flexibly changed, but once the fields are defined in MySQL, it is difficult to modify them. .
Compare from the perspective of query efficiency:
Redis -> MongoDB -> MySQL
3. Usage scenarios
- Game equipment data, game prop data
- Features: high frequency of modification
- Logistics industry data
- Features: geographic location information, massive data
- Live broadcast data, reward data, fan data
- Features: large amount of data, high frequency of modification
- log data
- Features: huge amount of data, variable structure
Are the above applicable scenarios for mengoDB? If you encounter similar scenarios in actual projects, you may choose to store data in mengoDB.
4. MongoDB architecture and terminology
MongoDB is the non-relational database that is most similar to a relational database. The reason why it is said this is because its architecture is similar to MySQL.
Let's get a preliminary understanding of MongoDB's architecture through comparison.
SQL terms/concepts | MongoDB terms/concepts | explain |
---|---|---|
database | database | database |
table | collection | Database table/collection |
row | document | a piece of data in the table |
column | field | Data fields/domains |
index | index | index |
table joins | Table join, MongoDB does not support | |
primary key | primary key | Primary key, MongoDB automatically sets the _id field as the primary key |
Knowing the architecture of MongoDB, let's take a look at its data structure.
MongoDB uses Bson to store data (Binary JSON), a Json-like data format.
Let's take a look at how a piece of data is displayed in the form of BSON. Let's compare it through MySQL.
MySQL:
MongoDB:
5. MongoDB command line operation
After understanding the basic concepts of MongoDB, we can get started with MongoDB.
5.1 Database and table operations
1. Query all databases.
show dbs
2. Switch the database through the use keyword.
use 切换的数据库
3. Create a database: In MongoDB, the database is automatically created. Use use to switch to a new database and insert data to automatically create the database.
use testdb2
Now query the database, and the database does not appear.
Insert data.
db.user.insert({id:1,name:'zhangsan'})
Inquire now.
4. Check the table.
show tables
show collections
5. Delete the collection (table).
db.user.drop()
6. Delete the database (you need to switch to the data to be deleted first)
use 要切换的数据库
delete
db.dropDatabase()
5.2 New data
1. Insert data (syntax: db.table name.insert(json string))
db.user.insert({id:1,username:'zhangsan',age:20})
2. Query data
db.user.find()
You may have questions here, why is there an underscore id? This is because MongoDB itself has a default primary key ID, which is this _id.
5.3 Update data
The update() method is used to update an existing document. The syntax format is as follows:
db.collection.update(
<query>,
<update>,
[
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>
]
)
Parameter Description:
- query : update query conditions, similar to where behind the sql update query.
- update : update object and some update operators (such as , ,, inc.$set), etc., can also be understood as the following set in the sql update query
- upsert : Optional, this parameter means whether to insert objNew if there is no updated record, true means insert, the default is false, not insert.
- multi : optional. The default value of mongodb is false. Only the first record found is updated. If this parameter is true, all multiple records found according to the conditions are updated.
- writeConcern : Optional, the level at which the exception is thrown.
Case:
db.user.update({
id:1},{
$set:{
age:22}})
To update non-existing data, no new data will be added by default.
db.user.update({id:2},{$set:{sex:1}})
5.4 Deletion of data
Delete data through the remove() method, the syntax is as follows:
db.collection.remove(
<query>,
{
justOne: <boolean>,
writeConcern: <document>
}
)
Parameter Description:
- query : (optional) Conditions for deleted documents.
- justOne : (optional) If set to true or 1, only one document will be deleted. If this parameter is not set, or the default value of false is used, all documents matching the condition will be deleted.
- writeConcern : (optional) The level at which the exception is thrown.
Code demo:
First we insert the data first.
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})
Delete data with age 22, only one.
db.user.remove({age:22},true)
Delete all data.
db.user.remove({})
5.5 Query data
The syntax format of MongoDB query data is as follows:
db.user.find([query],[fields])
- query : optional, use query operator to specify query conditions
- fields : Optional, use the projection operator to specify the returned keys. To return all key values in the document when querying, just omit this parameter (omitted by default).
Condition query:
operate | Format | example | Similar statements in RDBMS |
---|---|---|---|
equal | {<key>:<value> } |
db.col.find({"by":"一切总会归于平淡"}).pretty() |
where by = '一切总会归于平淡' |
less than | {<key>:{$lt:<value>}} |
db.col.find({"likes":{$lt:50}}).pretty() |
where likes < 50 |
less than or equal to | {<key>:{$lte:<value>}} |
db.col.find({"likes":{$lte:50}}).pretty() |
where likes <= 50 |
more than the | {<key>:{$gt:<value>}} |
db.col.find({"likes":{$gt:50}}).pretty() |
where likes > 50 |
greater than or equal to | {<key>:{$gte:<value>}} |
db.col.find({"likes":{$gte:50}}).pretty() |
where likes >= 50 |
not equal to | {<key>:{$ne:<value>}} |
db.col.find({"likes":{$ne:50}}).pretty() |
where likes != 50 |
Code demo:
Insert data:
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})
1. Query all data:
db.user.find()
2. Only query the id and username fields.
db.user.find({},{id:1,username:1})
3. Query the number of data items
db.user.find().count()
4. Query the data with id 1
db.user.find({id:1})
5. Query data whose age is less than or equal to 21
db.user.find({age:{$lte:21}})
6. Query id=1 or id=2
db.user.find({$or:[{id:1},{id:2}]})
7. Paging query: Skip() skips a few items, limit() queries the number of items
Skip 1 piece of data and query 2 pieces of data
db.user.find().limit(2).skip(1)
Sort by ID in reverse order, -1 is reverse order, 1 is forward order
db.user.find().sort({id:-1})
5.6 Index
In order to improve query efficiency, indexes are also supported in MongoDB.
Create index.
db.user.createIndex({'age':1})
Note: 1: Ascending index - 1: Descending index
View index.
db.user.getIndexes()
5.7. Execution plan
MongoDB query analysis can ensure whether our proposed indexes are effective and is an important tool for query statement performance analysis.
Insert 1000 pieces of data.
for(var i=1;i<1000;i++)db.user.insert({id:100+i,username:'name_'+i,age:10+i})
View the execution plan.
db.user.find({age:{$gt:100},id:{$lt:200}}).explain()
Tested without using indexes.
db.user.find({username:'zhangsan'}).explain()
winningPlan: best execution plan;
"stage": "FETCH", #Query method, common ones include COLLSCAN/full table scan, IXSCAN/index scan, FETCH/retrieve documents based on index, SHARD_MERGE/merge shard results, IDHACK/ Query against _id
6、SpringData-Mongo
After simply understanding the basic commands and indexes of MongoDB, we will get to the focus of this blog.
We need to operate MongoDB in the SpringBoot program. When it comes to operating MongoDB with JAVA code, there are no more than two ways.
- Using the official driver is similar to using the most basic JDBC driver to operate mysql.
- Use Spring Data Mongo DB provided by Spring Data.
Using the first method is too troublesome (I like to be lazy), so we use the second method.
Spring-data supports MongoDB. Using spring-data-mongodb can simplify the operation of MongoDB and encapsulate the underlying mongodb-driver.
Address: https://spring.io/projects/spring-data-mongodb
Using Spring-Data-MongoDB is very simple and only requires the following steps:
6.1 Environment setup
6.1.1 Create project
Don't choose springBoot version 3.0 or above. If your jdk version is 17 or above, I didn't say it.
6.1.2 Writing YML files
spring:
data:
mongodb:
uri: mongodb://192.168.136.160:27017/testdb2
6.2 Complete basic operations
The first step is to write entity classes.
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(value = "tb_person") // 指定实体类和MongoDB集合的映射关系
public class Person {
@Id
private ObjectId id;
@Field("name")
private String name;
@Field("age")
private int age;
@Field("address")
private String address;
}
The second step is to complete the CRUD operation through MongoTemplate.
Here it is demonstrated directly in the test class.
/**
* 注入模板对象
*/
@Resource
private MongoTemplate mongoTemplate;
/**
* 增加
*/
@Test
public void testSave() {
for (int i = 0; i < 10; i++) {
Person person = new Person();
//ObjectId.get():获取一个唯一主键字符串
person.setId(ObjectId.get());
person.setName("张三" + i);
person.setAddress("北京顺义" + i);
person.setAge(18 + i);
mongoTemplate.save(person);
}
}
Check all.
/**
* 注入模板对象
*/
@Resource
private MongoTemplate mongoTemplate;
/**
* 查询所有
*/
@Test
public void testFindAll() {
List<Person> list = mongoTemplate.findAll(Person.class);
for (Person person : list) {
System.out.println(person);
}
}
Query all people whose age is less than 20.
/**
* 注入模板对象
*/
@Resource
private MongoTemplate mongoTemplate;
/**
* 查询年龄小于20的所有人
*/
@Test
public void testFind() {
Query query = new Query(Criteria.where("age").lt(20)); //查询条件对象
//查询
List<Person> list = mongoTemplate.find(query, Person.class);
list.forEach(System.out::println);
}
Paging query.
/**
* 注入模板对象
*/
@Resource
private MongoTemplate mongoTemplate;
/**
* 分页查询
*/
@Test
public void testPage() {
Criteria criteria = Criteria.where("age").lt(30);
//1、查询总数
Query queryCount = new Query(criteria);
long count = mongoTemplate.count(queryCount, Person.class);
System.out.println(count);
//2、查询当前页的数据列表, 查询第二页,每页查询2条
Query queryLimit = new Query(criteria)
//设置每页查询条数
.limit(2)
//开启查询的条数 (page-1)*size
.skip(2);
List<Person> list = mongoTemplate.find(queryLimit, Person.class);
list.forEach(System.out::println);
}
Modify the age based on id.
/**
* 注入模板对象
*/
@Resource
private MongoTemplate mongoTemplate;
/**
* 修改:
* 根据id,修改年龄
*/
@Test
public void testUpdate() {
//1、条件
Query query = Query.query(Criteria.where("id").is("63d26be79e8d6402ffda6b21"));
//2、修改后的数据
Update update = new Update();
update.set("age", 99);
mongoTemplate.updateFirst(query, update, Person.class);
}
Delete: Delete based on id.
/**
* 注入模板对象
*/
@Resource
private MongoTemplate mongoTemplate;
@Test
public void testRemove() {
Query query = Query.query(Criteria.where("id").is("63d26be79e8d6402ffda6b21"));
mongoTemplate.remove(query, Person.class);
}