1、NoSQL簡介
NoSQL(NoSQL = Not Only SQL),意即反SQL運動,指的是非關系型的資料庫,是一項全新的資料庫革命性運動,早期就有人提出,發展至2009年趨勢越發高漲。NoSQL的擁護者們提倡運用非關系型的資料存儲,相對于目前鋪天蓋地的關系型資料庫運用,這一概念無疑是一種全新的思維的注入
為什幺使用NoSQL :
1、對資料庫高并發讀寫。
2、對海量資料的高效率存儲和通路。
3、對資料庫的高可擴充性和高可用性。
弱點:
1、資料庫事務一緻性需求
2、資料庫的寫實時性和讀實時性需求
3、對複雜的SQL查詢,特别是多表關聯查詢的需求
2、什麼是MongoDB ?
MongoDB 是由C++語言編寫的,是一個基于分布式檔案存儲的開源資料庫系統。
在高負載的情況下,添加更多的節點,可以保證伺服器性能。
MongoDB 旨在為WEB應用提供可擴充的高性能資料存儲解決方案。
MongoDB 将資料存儲為一個文檔,資料結構由鍵值(key=>value)對組成。MongoDB 文檔類似于 JSON 對象。字段值可以包含其他文檔,數組及文檔數組。
類似josn 格式。
适用場景
1、網站資料:Mongo非常适合實時的插入,更新與查詢,并具備網站實時資料存儲所需的複制及高度伸縮性。
2、緩存:由于性能很高,Mongo也适合作為資訊基礎設施的緩存層。在系統重新開機之後,由M ongo搭建的持久化緩存層可以避免下層的資料源過載。
3、大尺寸,低價值的資料:使用傳統的關系型資料庫存儲一些資料時可能會比較昂貴, 在此之前,很多時候程式員往往會選擇傳統的檔案進行存儲。
4、高伸縮性的場景:Mongo非常适合由數十或數百台伺服器組成的資料庫。Mongo的路線圖中已經包含對Map Reduce弓摩的内置支援。
5、用于對象及 JSON資料的存儲:Mongo的BSON資料格式非常适合文檔化格式的存儲 及查詢。
不适用場合
1、高度事務性的系統:例如銀行或會計系統。傳統的關系型資料庫目前還是更适用于需要大量原子性複雜事務的應用程式。
2、傳統的商業智能應用:針對特定問題的BI資料庫會對産生高度優化的查詢方式。對于此類應用,資料倉庫可能是更合适的選擇。
3、MongoDB 特點
1、MongoDB 是一個面向文檔存儲的資料庫,操作起來比較簡單和容易。
2、你可以在MongoDB記錄中設定任何屬性的索引 (如:FirstName=“Sameer”,Address=“8 Gandhi Road”)來實作更快的排序。
3、你可以通過本地或者網絡建立資料鏡像,這使得MongoDB有更強的擴充性。
4、如果負載的增加(需要更多的存儲空間和更強的處理能力) ,它可以分布在計算機網絡中的其他節點上這就是所謂的分片。
5、Mongo支援豐富的查詢表達式。查詢指令使用JSON形式的标記,可輕易查詢文檔中内嵌的對象及數組。
6、MongoDb 使用update()指令可以實作替換完成的文檔(資料)或者一些指定的資料字段 。
7、Mongodb中的Map/reduce主要是用來對資料進行批量處理和聚合操作。
8、Map和Reduce。Map函數調用emit(key,value)周遊集合中所有的記錄,将key與value傳給Reduce函數進行處理。
9、Map函數和Reduce函數是使用Javascript編寫的,并可以通過db.runCommand或mapreduce指令來執行MapReduce操作。
10、GridFS是MongoDB中的一個内置功能,可以用于存放大量小檔案。
11、MongoDB允許在服務端執行腳本,可以用Javascript編寫某個函數,直接在服務端執行,也可以把函數的定義存儲在服務端,下次直接調用即可。
12、MongoDB支援各種程式設計語言:RUBY,PYTHON,JAVA,C++,PHP,C#等多種語言。
13、MongoDB安裝簡單。
4、安裝mongodb
#拉取鏡像
docker pull mongo:latest
#建立和啟動容器
docker run -d --restart=always -p 27017:27017 --name mymongo -v /data/db:/data/db -d mongo
#進入容器
docker exec -it mymongo/bin/bash
#使用MongoDB用戶端進行操作
mongo
show dbs #查詢所有的資料庫
admin 0.000GB
config 0.000GB
local 0.000GB
5 具體概念
SQL術語/概念 | MongoDB術語/概念 | 解釋/說明 |
---|---|---|
database | database | 資料庫 |
table | collection | 資料庫表/集合 |
row | document | 資料記錄行/文檔 |
column | field | 資料字段/域 |
index | index | 索引 |
table | joins | 表連接配接,MongoDB不支援 |
primary key | primary key | 主鍵,MongoDB自動将_id字段設定為主鍵 |
操作
資料庫常用操作:
一個mongodb中可以建立多個資料庫
1、 Help檢視指令提示
db.help();
2、 切換/建立資料庫
use test
如果資料庫不存在,則建立資料庫,否則切換到指定資料庫
3、 查詢所有資料庫
show dbs;
4、 删除目前使用資料庫
db.dropDatabase();
5、 檢視目前使用的資料庫
db.getName();
6、 顯示目前db狀态
db.stats();
7、 目前db版本
db.version();
8、 檢視目前db的連結機器位址
db.getMongo();
集合常用操作
集合就是 MongoDB 文檔組,類似于 RDBMS (關系資料庫管理系統:Relational Database Management System)中的表格。
集合存在于資料庫中,集合沒有固定的結構,這意味着你在對集合可以插入不同格式和類型的資料,但通常情況下我們插入集合的資料都會有一定的關聯性。
常用指令:
1、 建立一個集合(table)
db.createCollection( “collName”);
2、 得到指定名稱的集合(table )
db.getCollection(“user”);
資料類型
資料類型 | 描述 |
---|---|
String | 字元串。存儲資料常用的資料類型。在 MongoDB 中,UTF-8 編碼的字元串才是合法的。 |
Integer | 整型數值。用于存儲數值。根據你所采用的伺服器,可分為 32 位或 64 位。 |
Boolean | 布爾值。用于存儲布爾值(真/假)。 |
Double | 雙精度浮點值。用于存儲浮點值。 |
Min/Max keys | 将一個值與 BSON(二進制的 JSON)元素的最低值和最高值相對比。 |
Arrays | 用于将數組或清單或多個值存儲為一個鍵。 |
Timestamp | 時間戳。記錄文檔修改或添加的具體時間。 |
Object | 用于内嵌文檔。 |
Null | 用于建立空值。 |
Symbol | 符号。該資料類型基本上等同于字元串類型,但不同的是,它一般用于采用特殊符号類型的語言。 |
Date | 日期時間。用 UNIX 時間格式來存儲目前日期或時間。你可以指定自己的日期時間:建立 Date 對象,傳入年月日資訊。 |
Object | ID 對象 ID。用于建立文檔的 ID。 |
Binary Data | 二進制資料。用于存儲二進制資料。 |
Code | 代碼類型。用于在文檔中存儲 JavaScript 代碼。 |
Regular expression | 正規表達式類型。用于存儲正規表達式。 |
操作
1.1 INSERT
db.User.save({name:‘zhangsan’,age:21,sex:true})
db.User.find()
{"_id": Objectld(“4f69e680c9106ee2ec95da66”), “name”: “zhangsan”, “age”: 21,
“sex”: true}
_id組合
Objectld是、id”的預設類型。Objectld使用12位元組的存儲空間,每個位元組二位十六進制數字, 是一個24位的字元串
- 時間戳:時間不斷變化的
-
機器:主機的唯_辨別碼。通常是機器主機名的散列值,這樣可以確定不同主機
生成不同的Objectld ,不産生沖突。
-
PID:為了確定在同一台機器上并發的多個程序産生的Objectld是唯一的,
是以加上程序辨別符(PID).
-
計數器:前9個位元組保證了同一秒鐘不同機器不同程序産生的Objectld是唯一的。
後3個位元組就是一個自動增加的計數器,確定相同程序同一秒産生的Objectld也是
不一樣。同一秒最多允許每個程序擁有IS 777 2托個不同的Objectld。
1.2 Query
1、WHERE
select * from User where name = ‘zhangsan’
db.User.find({name:“zhangsan”})
2、FIELDS
select name, age from User where age = 21
db.User.find({age:21}, {‘name’:1, ‘age’:1})
3、SORT
在 MongoDB 中使用 sort() 方法對資料進行排序,sort() 方法可以通過參數指定排序的字段,并使用 1 和 -1 來指定排序的方式,其中 1 為升序排列,而 -1 是用于降序排列。
select * from User order by age
db.User.find().sort({age:1})
4、SUCE
在 MongoDB 中使用 limit()方法來讀取指定數量的資料,skip()方法來跳過指定數量的資料
select * from User skip 2 limit 3
db.User.find().skip(0).limit(3)
5、IN
select * from User where age in (21, 26, 32)
db.User.find({age:{$in:[21,26,32]}})
6、COUNT
select count(*) from User where age >20
db.User.find({age:{$gt:20}}).count()
7、or
select * from User where age = 21 or age = 28
db.User.find({$or:[{age:21}, {age:28}]})
1.3 Update
可直接用類似T-SQL條件表達式更新,或用SaveO更新從資料庫傳回到文檔對象。
update Userset age = 100, sex = 0 where name = ‘user1’
db.User.update({name:“zhangsan”}, {$set:{age:100, sex:0}})
Update()有幾個參數需要注意。
db.collection.update(criteria, objNew, upsert, mult)
criteria:需要更新的條件表達式
objNew:更新表達式
upsert:如FI标記錄不存在,是否插入新文檔。
multi:是否更新多個文檔。
1.4 Remove
removeO用于删除單個或全部文檔,删除後的文檔無法恢複。
db.User.remove(id)
//移除對應id的行
db.User.remove({})
//移除所有
1.5 aggregate
MongoDB中聚合(aggregate)主要用于處理資料(諸如統計平均值,求和等),并傳回計算後的資料結果。有點類似sql語句中的 count(*)
1.5.1 插入資料
db.article.insert({
title: ‘MongoDB Overview’,
description: ‘MongoDB is no sql database’,
by_user: ‘runoob.com’,
url: ‘http://www.runoob.com’,
tags: [‘mongodb’, ‘database’, ‘NoSQL’],
likes: 100
})
db.article.insert({
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
})
db.article.insert({
title: ‘Neo4j Overview’,
description: ‘Neo4j is no sql database’,
by_user: ‘Neo4j’,
url: ‘http://www.neo4j.com’,
tags: [‘neo4j’, ‘database’, ‘NoSQL’],
likes: 750
})
2.5.2 統計sum
現在我們通過以上集合計算每個作者所寫的文章數
select by_user, count(*) from article group by by_user
db.article.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : {$sum : 1}}}])
{
“result” : [
{
“_id” : “runoob.com”,
“num_tutorial” : 2
},
{
“_id” : “Neo4j”,
“num_tutorial” : 1
}
],
“ok” : 1
}
常見聚合表達式:
$sum | 計算總和。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { s u m : " sum : " sum:"likes"}}}]) |
---|---|---|
$avg | 計算平均值 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { a v g : " avg : " avg:"likes"}}}]) |
$min | 擷取集合中所有文檔對應值得最小值。 db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { m i n : " min : " min:"likes"}}}]) | |
$max | 擷取集合中所有文檔對應值得最大值。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { m a x : " max : " max:"likes"}}}]) |
$push | 在結果文檔中插入值到一個數組中。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", url : { p u s h : " push: " push:"url"}}}]) |
$addToSet | 在結果文檔中插入值到一個數組中,但不建立副本。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", url : { a d d T o S e t : " addToSet : " addToSet:"url"}}}]) |
$first | 根據資源文檔的排序擷取第一個文檔資料。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", first_url : { f i r s t : " first : " first:"url"}}}]) |
$last | 根據資源文檔的排序擷取最後一個文檔資料 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", last_url : { l a s t : " last : " last:"url"}}}]) |
索引
索引通常能夠極大的提高查詢的效率,如果沒有索引,MongoDB在讀取資料時必須掃描集合中的每個檔案并選取那些符合查詢條件的記錄。
這種掃描全集合的查詢效率是非常低的,特别在處理大量的資料時,查詢可以要花費幾十秒甚至幾分鐘,這對網站的性能是非常緻命的。
索引是特殊的資料結構,索引存儲在一個易于周遊讀取的資料集合中,索引是對資料庫表中一列或多列的值進行排序的一種結構。
db.User.createIndex({“name”:1})
文法中 name值為你要建立的索引字段,1 為指定按升序建立索引,如果你想按降序來建立索引指定為 -1 即可
springboot 內建:
兩種方式 MongoTemplate
MongoRepostiory:
springboot 依賴:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
2.application添加配置
//ip位址 / 資料庫名
spring.data.mongodb.uri=mongodb://192.168.40.133:27017/test
MongoTemplate類:
- Entity 類: user
@Data
@Document("User")
public class User {
@Id
private String id;
private String name;
private Integer age;
private String email;
private String createDate;
}
常用方法
mongoTemplate.findAll(User.class): 查詢User文檔的全部資料
mongoTemplate.findById(, User.class): 查詢User文檔id為id的資料
mongoTemplate.find(query, User.class);: 根據query内的查詢條件查詢
mongoTemplate.upsert(query, update, User.class): 修改
mongoTemplate.remove(query, User.class): 删除
mongoTemplate.insert(User): 新增
Query對象
1、建立一個query對象(用來封裝所有條件對象),再建立一個criteria對象(用來建構條件)
2、 精準條件:criteria.and(“key”).is(“條件”)
模糊條件:criteria.and(“key”).regex(“條件”)
3、封裝條件:query.addCriteria(criteria)
4、大于(建立新的criteria):Criteria gt = Criteria.where(“key”).gt(“條件”)
小于(建立新的criteria):Criteria lt = Criteria.where(“key”).lt(“條件”)
5、Query.addCriteria(new Criteria().andOperator(gt,lt));
6、一個query中隻能有一個andOperator()。其參數也可以是Criteria數組。
7、排序 :query.with(new Sort(Sort.Direction.ASC, “age”). and(new Sort(Sort.Direction.DESC, “date”)))
具體方法:
@SpringBootTest
class DemomogoApplicationTests {
@Autowired
private MongoTemplate mongoTemplate;
//添加
@Test
public void createUser() {
User user = new User();
user.setAge(20);
user.setName("test");
user.setEmail("[email protected]");
User user1 = mongoTemplate.insert(user);
System.out.println(user1);
}
//查詢所有
@Test
public void findUser() {
List<User> userList = mongoTemplate.findAll(User.class);
System.out.println(userList);
}
//根據id查詢
@Test
public void getById() {
User user =
mongoTemplate.findById("5ffbfa2ac290f356edf9b5aa", User.class);
System.out.println(user);
}
//條件查詢
@Test
public void findUserList() {
Query query = new Query(Criteria
.where("name").is("test")
.and("age").is(20));
List<User> userList = mongoTemplate.find(query, User.class);
System.out.println(userList);
}
//模糊查詢
@Test
public void findUsersLikeName() {
String name = "est";
String regex = String.format("%s%s%s", "^.*", name, ".*$");
Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
Query query = new Query(Criteria.where("name").regex(pattern));
List<User> userList = mongoTemplate.find(query, User.class);
System.out.println(userList);
}
//分頁查詢
@Test
public void findUsersPage() {
String name = "est";
int pageNo = 1;
int pageSize = 10;
Query query = new Query();
String regex = String.format("%s%s%s", "^.*", name, ".*$");
Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
query.addCriteria(Criteria.where("name").regex(pattern));
int totalCount = (int) mongoTemplate.count(query, User.class);
List<User> userList = mongoTemplate.find(query.skip((pageNo - 1) * pageSize).limit(pageSize), User.class);
Map<String, Object> pageMap = new HashMap<>();
pageMap.put("list", userList);
pageMap.put("totalCount",totalCount);
System.out.println(pageMap);
}
//修改
@Test
public void updateUser() {
User user = mongoTemplate.findById("5ffbfa2ac290f356edf9b5aa", User.class);
user.setName("test_1");
user.setAge(25);
user.setEmail("[email protected]");
Query query = new Query(Criteria.where("_id").is(user.getId()));
Update update = new Update();
update.set("name", user.getName());
update.set("age", user.getAge());
update.set("email", user.getEmail());
UpdateResult result = mongoTemplate.upsert(query, update, User.class);
long count = result.getModifiedCount();
System.out.println(count);
}
//删除操作
@Test
public void delete() {
Query query =
new Query(Criteria.where("_id").is("5ffbfa2ac290f356edf9b5aa"));
DeleteResult result = mongoTemplate.remove(query, User.class);
long count = result.getDeletedCount();
System.out.println(count);
}
}
mongoRepository 類
1、不是随便聲明的,而需要符合一定的規範
2、 查詢方法以find | read | get開頭
3、 涉及條件查詢時,條件的屬性用條件關鍵字連接配接
4、 要注意的是:條件屬性首字母需要大寫
5、 支援屬性的級聯查詢,但若目前類有符合條件的屬性則優先使用,而不使用級聯屬性,若需要使用級聯屬性,則屬性之間使用_強制進行連接配接
4.2
package com.atguigu.mongodb.repository;
import com.atguigu.mongodb.entity.User;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UserRepository extends MongoRepository<User, String> {
}
@SpringBootTest
class DemomogoApplicationTests1 {
@Autowired
private UserRepository userRepository;
//添加
@Test
public void createUser() {
User user = new User();
user.setAge(20);
user.setName("張三");
user.setEmail("[email protected]");
User user1 = userRepository.save(user);
}
//查詢所有
@Test
public void findUser() {
List<User> userList = userRepository.findAll();
System.out.println(userList);
}
//id查詢
@Test
public void getById() {
User user = userRepository.findById("5ffbfe8197f24a07007bd6ce").get();
System.out.println(user);
}
//條件查詢
@Test
public void findUserList() {
User user = new User();
user.setName("張三");
user.setAge(20);
Example<User> userExample = Example.of(user);
List<User> userList = userRepository.findAll(userExample);
System.out.println(userList);
}
//模糊查詢
@Test
public void findUsersLikeName() {
//建立比對器,即如何使用查詢條件
ExampleMatcher matcher = ExampleMatcher.matching() //建構對象
.withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING) //改變預設字元串比對方式:模糊查詢
.withIgnoreCase(true); //改變預設大小寫忽略方式:忽略大小寫
User user = new User();
user.setName("三");
Example<User> userExample = Example.of(user, matcher);
List<User> userList = userRepository.findAll(userExample);
System.out.println(userList);
}
//分頁查詢
@Test
public void findUsersPage() {
Sort sort = Sort.by(Sort.Direction.DESC, "age");
//0為第一頁
Pageable pageable = PageRequest.of(0, 10, sort);
//建立比對器,即如何使用查詢條件
ExampleMatcher matcher = ExampleMatcher.matching() //建構對象
.withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING) //改變預設字元串比對方式:模糊查詢
.withIgnoreCase(true); //改變預設大小寫忽略方式:忽略大小寫
User user = new User();
user.setName("三");
Example<User> userExample = Example.of(user, matcher);
//建立執行個體
Example<User> example = Example.of(user, matcher);
Page<User> pages = userRepository.findAll(example, pageable);
System.out.println(pages);
}
//修改
@Test
public void updateUser() {
User user = userRepository.findById("5ffbfe8197f24a07007bd6ce").get();
user.setName("張三_1");
user.setAge(25);
user.setEmail("[email protected]");
User save = userRepository.save(user);
System.out.println(save);
}
//删除
@Test
public void delete() {
userRepository.deleteById("5ffbfe8197f24a07007bd6ce");
}
}