天天看點

上手mongodb

上手MongoDB

MongoDB 是一個跨平台的,面向文檔的資料庫,如果你了解spring-data-jpa的使用, 那麼恭喜你,你已經可以使用mongodb做開發了

使用這種類型的資料庫還是挺友善的,最小的存儲機關是一個文檔,但是文檔有什麼字段,有多少字段它都不關心,而mysql這樣的典型的關系型資料庫,開發之前得把表設計的明明白白的,說不定還得預留幾個字段以備不時之需,因為後續再改就麻煩了

。它支援的資料結構非常松散,是類似 JSON 的 BSON 格式,是以可以存儲比較複雜的資料類型。

體系結構

MongoDB Mysql
database database
collection 資料表
document 表中的一行記錄

一個MongoDB執行個體支援多個database并存,同時一個database中可以包含多個collection,是以大家都說它是介于關系資料庫和非關系資料庫之間,因為它的組成結構真的特别像關系型資料庫

支援的資料類型

資料類型名 BSON
null {"XXX":null}
布爾值: {"XXX":true/false}
int {"XXX":NumberInt("1")}
Long {"XXX":NumberLong("1")}
字元串 {"XXX":"啊哈哈哈"}
日期 {"XXX":new Date()}
正則 {"XXX":null}
布爾值: {"XXX":/[abc]/}
數組 {"XXX":["a","b","c"]}
文檔的嵌套: {"XXX":{"YYY":3}}
對象id {"XXX":objectId()}

注意點:

  • 當我們再在指令行視窗通過指令行進行資料的讀寫時,如果我們這樣寫 {"XXX",2}, 它會預設把2處理成浮點類型,而不是整形
  • 每一個文檔唯一身份id是 _id , 前面有個下劃線

使用指令行進行資料的讀寫

點選文檔官網

  • 開啟本地的mongo伺服器(用來儲存資料)打開之後,就别關了

預設使用的端口是 27017

mongod -dbpath=指定檔案夾當作資料存儲路徑 --port 端口号           
  • 連接配接資料庫(用戶端,進行CRUD)
// 在本機直接用下面的指令,模拟連接配接本機的mongodb
mongo
// 連接配接遠端的mongo
mongo 192.168.88.88           
  • 退出
exit           
  • 選擇資料庫

預設選中的資料庫是test庫

// 如果資料名不存在,預設直接把它建立出來,并且直接選中它使用
user 資料庫名           
  • 檢視目前資料庫
db           
  • 儲存一條資料
入參位置的bson, 注意key的部分是沒有雙引号的
db.集合名.insert({content:"哈哈,儲存了資料"})           
  • 查詢全部資料, 預設按照_id從小到大排序
db.集合名.find()           
  • 傳回滿足條件的全部資料
入參部分的查詢條件 bson同樣是json格式
db.集合名.find({id:"123"})           
  • 傳回滿足條件的第一條資料
入參部分的查詢條件 bson同樣是json格式
db.集合名.findOne({id:"123"})           
  • 根據限制的數量, 傳回滿足條件的資料
入參部分的查詢條件 bson同樣是json格式
db.集合名.find({id:"123"}).limit(1)           
  • 更新文檔
db.集合名.update(條件,修改後的資料)

// 下面的這條修改語句存在問題,隻會保留name字段
db.集合.update({_id:"1"},{name:"新名字"})

// 保留其他字段的寫法 db.集合名.update({條件},{$set:{新的值} })
db.集合.update({_id:"1"},{$set:{name:"新名字"}})
           
  • 删除文檔
db.集合.remove(條件)

// 删除全部
db.集合.remove({})            
  • 統計數量
db.spit.count()

db.spit.count({條件})           
  • 使用正則實作.模糊查詢

    /将被模糊查詢的字元串/

db.集合名.find({content:/将被模糊查詢的字元串/})

//比對以XXX開頭的文檔
db.集合名.find({content:/^XXX/})           
  • 大于,小于,不等于
db.集合名.find({"參考的字段":{$gt:value}}) // 查找參考的字段大于value值的文檔
$lt 小于
$lte 小于等于   
$gte 大于等于
$ne 不等于            
  • 包含和不包含
db.集合名.find({_id:{$in:["1","2","3"]}})
db.集合名.find({_id:{$nin:["1","2","3"]}})           
  • 條件連接配接
$and:[{},{},{}]
// 查詢id 大于1000,小于2000的文檔
db.集合名.find({$and:[{_id:{$gte:1000}},{_id:{$lte:2000}}]})

$or:[{},{},{}]           
  • 實作列值的增長
db.集合名.update({_id:"12"},{$inc:{number:NumberInt(1)}})           
  • 按照某個字段排序
db.集合名.find({}).sort(字段:1) // 1是升序

db.集合名.find({}).sort(字段:-1) // -1是降序

// 先按照字段1升序, 如果字段1的值相同,按照字段2降序排序
db.集合名.find({}).sort(字段:1| 字段2:-1) 

           

Java操作MongoDB

添加坐标

<dependency>
      <groupId>org.mongodb</groupId>
      <artifactId>mongodb-driver</artifactId>
      <version>3.6.3</version>
  </dependency>
           

配置檔案

server:
  port: 9002
  data:
    mongodb:
      host: 192.168.88.130
      database: 資料庫名字           

使用mongo官方提供的java的驅動包,相當于jdbc

// 連接配接mongo伺服器
MongoClient client = new MongoClient("192.168.88.130");
// 得到想操作的資料庫
MongoDatabase db = client.getDatabase("資料庫名");
// 得到想要操作的集合
MongoCollection<Document> collection = db.getCollection("集合名");

// todo CRUD with collection

// 釋放資源
client.close();
           

查詢全部

FindIterable<Document> documents = collection.find();

for (Document document : documents) {
        System.out.println(document);
    }           

根據限制條件查詢

  • 查詢出content字段為"我很開心"全部文檔
// 條件查詢限制為  userid==123
BasicDBObject bson = new BasicDBObject("content", "我很開心");

FindIterable<Document> documents = collection.find(bson);           
  • 封裝條件,查詢通路量大于1000的,可以還可以更換成gt gte等等
//    find(visit:{$gt:1000})
BasicDBObject bson = new BasicDBObject("visits", new BasicDBObject("$gt",1000));

FindIterable<Document> documents = collection.find(bson);           

我發現如果是使用_id當作限制條件,此時如果_id的類型是原生的objectid類型的話,是查詢不處任何結果的,但是如果換成我們自定義的_id, 就可以當成限制條件比對出相應的文檔

添加一個文檔

_id不能重複

HashMap<String, Object> map = new HashMap<>();
map.put("_id","10");
map.put("content","啊");
map.put("article","嘻嘻嘻嘻嘻");
Document document = new Document(map);
collection.insertOne(document);           

添加嵌套文檔

Document document = new Document();

// 插入普通字段
document.put("_id","123");
document.put("key1","value1");
document.put("key2","value2");
document.put("key3","value3");

Document doc = new Document();
doc.put("key4","value4");
// 嵌套文檔
document.put("docDetail",doc);

collection.insertOne(document)           

更新

  • 更新數值類型的數,在原來的基礎上增加
// 使用$inc ,在将入參2位置對應的文檔的指定字段增加指定的數
BasicDBObject newDoc = new  BasicDBObject().append("$inc",new BasicDBObject().append("thumbup",1));

// 第一個參數是限制條件找到要被更新的bson, 第二個參數是将被改變的值
collection.updateOne(new  BasicDBObject().append("content","我是新的content"),newDoc);
           
  • 更新普通字元串類型
// 使用$set ,在将入參2位置對應的文檔的指定字段更新為指定的值
BasicDBObject newDoc = new  BasicDBObject().append("$set",new BasicDBObject().append("nickname","朱昌武"));

// 第一個參數是限制條件找到要被更新的bson, 第二個參數是将被改變的值
collection.updateOne(new  BasicDBObject().append("_id","1"),newDoc);           

替換文檔

同樣,如果入參1位置的過濾條件,使用的_id是原生ObjectId類型的話,比對不出任何結果

BasicDBObject bson = new BasicDBObject("_id", "5d4fd7cb92cb2acaf109a46e");

//   Document filter = new Document();
//   filter.append("_id", "5d4fd7cb92cb2acaf109a46e");

Document replacement = new Document();
replacement.append("key1","我替換了一第一個文檔");

collection.replaceOne(bson,replacement);           

删除文檔

// 删除一個
Document filter = new Document();
filter.append("hello", "world");

collection.deleteOne(filter);
 
// 删除多個
Document document = new Document();

// 第一個參數是限制條件找到要被更新的bson, 第二個參數是将被改變的值
 collection.deleteMany(document);           

SpringDataMongoDB

編寫Repository層,進行簡單的CRUD

spring-data-mongodb的用法和jpa是一樣的,Spring很強大,一統天下

  • 引入啟動器
  • 配置檔案,和上面的一樣
  • 編寫DAO層
public interface SpitRepository   extends MongoRepository<Spit,String> {}           

它内置了簡單的增删改查的方法,可以分頁,也可以使用Spring對jpql的進階封裝比如findByXXX等

MongoTemplate的使用:

更新

如果被更新的文檔沒有該條記錄,就會建立出這個field,然後指派

Query query = new Query();
Criteria criteria = new Criteria();
query.addCriteria(Criteria.where("_id").is("5d50cee71e5a931d2cd72e43"));

Update update = new Update();
update.set("key1","新的值");

// 隻會更新滿足條件的第一條
入參位置1  query作用: 根據條件找出對應的doc
入參位置2  update作用:  進行更新的操作
mongoTemplate.updateFirst(query,update,"集合");           

使用下面的函數也能達到相同更新的效果

mongoTemplate.upsert(query,update,"集合");           

批量更新:

批量更新滿足條件的doc,隻要前面的條件滿足, 就會被更新, 不存在的字段會添加上去, 存在的被更新掉

Query query = new Query();
query.addCriteria(Criteria.where("nickname").is("恩恩"));

Update update = new Update();
update.set("share","2");  // 同樣, key8不存在,就新添加進去

// 隻會更新滿足條件的第一條
mongoTemplate.updateMulti(query,update,"spit");           

僅僅更新滿足條件的第一個

Query query = new Query();
query.addCriteria(Criteria.where("nickname").is("恩恩"));

Update update = new Update();
update.set("share","2");  // 同樣, key8不存在,就新添加進去

// 隻會更新滿足條件的第一條
mongoTemplate.updateFirst(query,update,"spit");           

給指定的字段增加指定的數量, 注意點是, 如果嘗試對字元串增加指定的數,不報錯,但是也不會改變原來的值

Query query = new Query();
query.addCriteria(Criteria.where("_id").is("1"));

Update update = new Update();
update.inc("thumbup",3); // 給指定的字段增加指定的數量

// 隻會更新滿足條件的第一條
mongoTemplate.updateFirst(query,update,"spit");
           

重命名文檔的某個key

Query query = new Query();
Criteria criteria = new Criteria();
query.addCriteria(Criteria.where("_id").is("1"));

Update update = new Update();
update.rename("_class","新的class"); // 給指定的字段增加指定的數量

// 隻會更新滿足條件的第一條
mongoTemplate.updateFirst(query,update,"spit");           

移除key

update.unset("新的class");           

在現有的文檔基礎上,嵌入文檔

Query query = new Query();
Criteria criteria = new Criteria();
query.addCriteria(Criteria.where("_id").is("1"));

Update update = new Update();

Spit spit = new Spit();
spit.set_id("666");
spit.setContent("我的被嵌套進來的文檔");

update.addToSet("childSpit",spit);
// 隻會更新滿足條件的第一條
mongoTemplate.updateFirst(query,update,"spit");           

修改被嵌入的文檔

Query query = new Query();
Criteria criteria = new Criteria();
// 通過  添加條件定位出 指定的嵌套文檔
query.addCriteria(Criteria.where("_id").is("1").and("childSpit._id").is("666"));

Update update = new Update();

// todo 通過這樣條件  字段名.$.field
update.set("childSpit.$.content","嵌套文檔的conntent被改變了");

// 隻會更新滿足條件的第一條
mongoTemplate.updateFirst(query,update,"spit");           

删除嵌套文檔

Query query = new Query();
Criteria criteria = new Criteria();
// 通過  添加條件定位出 指定的嵌套文檔
query.addCriteria(Criteria.where("_id").is("1").and("childSpit._id").is("666"));

Update update = new Update();

update.unset("childSpit.$");

// 隻會更新滿足條件的第一條
mongoTemplate.updateFirst(query,update,"spit");           

使用:MongoTemplate 提高效率的場景

在點贊的業務中,給某個文章點贊的邏輯如下:

  • 前端送出文章的id, 後端根據id查詢一次資料庫,把文章查出來
  • 給文章的贊數+1
  • 把文章更新進資料庫
前前後後使用了兩次查詢,下面使用MongoTemplate,可以實作和資料庫一次互動,完成更新
Query query = new Query();
query.addCriteria(Criteria.where("_id").is("前端送出的id"));
Update update = new Update();
update.inc("贊的字段",1); // 自增1
mongoTemplate.updateFirst(query,update,"集合名字");           

參考部落格:illustriousness

參考部落格: tbyang