# MongoDB 基本指令操作 [![hackmd-github-sync-badge](https://hackmd.io/voDdxQGCRVOm7dfRA-VQNQ/badge)](https://hackmd.io/voDdxQGCRVOm7dfRA-VQNQ) ###### tags: `DB` `NoSQL` ### MongoDB Docker基本安裝 下載鏡像 ``` docker pull mongo ``` 在本地端建立一個可以儲存DB資料的資料夾 mongodb_data ``` mkdir mongodb_data ``` 啟動並轉port ``` docker run --name test_mongo -v $(pwd)/mongodb_data:/data/db -d -p 27017:27017 --rm mongo ``` 進入docker ``` docker -it test_mongo bash ``` ### 進入DB命令列(Shell) ``` mongosh ``` ### 基本指令操作 CRUD #### 顯示目前操作DB ``` testdb> db testdb ``` #### 檢視DB ``` testdb> show dbs admin 40.00 KiB config 108.00 KiB local 40.00 KiB testdb 72.00 KiB ``` #### 切換DB(當沒有該DB時自動創建) ``` admin> use testdb switched to db testdb ``` #### 刪除DB ``` testdb> use testdb2 switched to db testdb2 testdb2> db.dropDatabase() { ok: 1, dropped: 'testdb2' } ``` #### 創建集合collections ``` testdb> db.createCollection('testCollect2') { ok: 1 } ``` #### 查看已有集合 可使用 show collections 或 show tables ``` testdb> show collections testCollect testCollect2 testdb> show tables testCollect testCollect2 ``` 在 MongoDB 中,你不需要創建集合。當你插入一些資料时,MongoDB會自動創建集合。 ``` testdb> db.testCollect3.insertOne({'name':'kelly'}) { acknowledged: true, insertedId: ObjectId("6388575272d61551eaf91e78") } testdb> show tables testCollect testCollect2 testCollect3 ``` #### 刪除集合 > drop() ``` testdb> show tables testCollect testCollect2 testCollect3 testdb> db.testCollect3.drop() true testdb> show tables testCollect testCollect2 ``` #### 新增資料 新增一筆資料 > insertOne() ``` testdb> db.rooms.insertOne( {name:"單人房",price:1000,rating:4.5} ) { acknowledged: true, insertedId: ObjectId("63885aec72d61551eaf91e79") } ``` 新增多筆資料 > insertMany() ``` testdb> db.rooms.insertMany( [ { "rating": 4.3, "price": 1500, "name": "豪華單人房" }, { "rating": 4.8, "price": 2000, "name": "雙人房" } ] ) { acknowledged: true, insertedIds: { '0': ObjectId("63885b6d72d61551eaf91e7a"), '1': ObjectId("63885b6d72d61551eaf91e7b") } } ``` 也可以把資料存入到一個變數中 ``` testdb> document=({'name':'test nosql'}) { name: 'test nosql' } testdb> db.rooms.insertOne(document) { acknowledged: true, insertedId: ObjectId("63885e4f2facbdf49a82817d") } ``` #### 更新資料 用于更新已存在的資料。語法格式如下: > update() * query : update的查詢條件,類似sql update查詢内where後面的。 * update : update的對象和一些更新的操作符(如$,$inc...)等,也可以理解為sql update查詢内set後面的 * upsert : 可選,这個参数的意思是,如果不存在update的紀錄,是否插入objNew,true為插入,默認是false,不插入。 * multi : 可選,mongodb 默認是false,只更新找到的第一筆紀錄,如果这這個参数為true,就把按條件查出来多條紀錄全部更新。 * writeConcern :可選,抛出異常的级别。 ``` db.collection.update( <query>, <update>, { upsert: <boolean>, multi: <boolean>, writeConcern: <document> } ) ``` 更新剛剛新增的 {name:'test nosql'} ``` testdb> db.rooms.update({'name':'test nosql'},{$set:{'name':'test nosql update'}}) DeprecationWarning: Collection.update() is deprecated. Use updateOne, updateMany, or bulkWrite. { acknowledged: true, insertedId: null, matchedCount: 1, modifiedCount: 1, upsertedCount: 0 } testdb> db.rooms.find().pretty() [ { _id: ObjectId("63885aec72d61551eaf91e79"), name: '單人房', price: 1000, rating: 4.5 }, { _id: ObjectId("63885b6d72d61551eaf91e7a"), rating: 4.3, price: 1500, name: '豪華單人房' }, { _id: ObjectId("63885b6d72d61551eaf91e7b"), rating: 4.8, price: 2000, name: '雙人房' }, { _id: ObjectId("63885e4f2facbdf49a82817d"), name: 'test nosql update' } ] ``` 可以看到名稱(name)由原来的 "test nosql" 更新為了 "test nosql update"。 以上語句只会修改第一條發現的資料,如果你要修改多條相同的資料,則需要設置 multi 参数為 true。 ``` testdb> db.rooms.update({'name':'test nosql'},{$set:{'name':'test nosql update'}},{multi:true}) ``` 更新一筆資料欄位 > updateOne() ``` testdb> db.rooms.updateOne({"_id":ObjectId("63885e4f2facbdf49a82817d")},{$set:{"name":"test nosql updateOne"}}) { acknowledged: true, insertedId: null, matchedCount: 1, modifiedCount: 1, upsertedCount: 0 } testdb> db.rooms.find().pretty() [ { _id: ObjectId("63885aec72d61551eaf91e79"), name: '單人房', price: 1000, rating: 4.5 }, { _id: ObjectId("63885b6d72d61551eaf91e7a"), rating: 4.3, price: 1500, name: '豪華單人房' }, { _id: ObjectId("63885b6d72d61551eaf91e7b"), rating: 4.8, price: 2000, name: '雙人房' }, { _id: ObjectId("63885e4f2facbdf49a82817d"), name: 'test nosql updateOne' } ] ``` 更新多個值(filter 篩選 >$set 更換設定) > updateMany() ``` testdb> db.rooms.updateMany( {rating:{$gt:4.5}}, {$set:{price:300}} ) { acknowledged: true, insertedId: null, matchedCount: 1, modifiedCount: 1, upsertedCount: 0 } testdb> db.rooms.find().pretty() [ { _id: ObjectId("63885aec72d61551eaf91e79"), name: '單人房', price: 1000, rating: 4.5 }, { _id: ObjectId("63885b6d72d61551eaf91e7a"), rating: 4.3, price: 1500, name: '豪華單人房' }, { _id: ObjectId("63885b6d72d61551eaf91e7b"), rating: 4.8, price: 300, name: '雙人房' }, { _id: ObjectId("63885e4f2facbdf49a82817d"), name: 'test nosql updateOne' } ] ``` 根據過濾器替換集合中的單個資料 > replaceOne() * filter: 指定一個空資料以替換集合中返回的第一筆資料 * replacement: 替換資料 * upsert: 可選,这個参数的意思是,如果不存在update的紀錄,是否插入objNew,true為插入,默認是false,不插入。 * writeConcern: 可選的。表達書面關切的文件。省略使用默認的寫關注。 * collation: 可選的。指定用於操作的排序規則。 * hint: 可選的。指定用於支持過濾器的索引的文檔或字符串。 ``` db.collection.replaceOne( <filter>, <replacement>, { upsert: <boolean>, writeConcern: <document>, collation: <document>, hint: <document|string> // Available starting in 4.2.1 } ) ``` 更新單人房價格與評分 ``` testdb> db.rooms.replaceOne({'name':'單人房'},{'name':'單人房','price':1100, 'rating':4.4}) { acknowledged: true, insertedId: null, matchedCount: 1, modifiedCount: 1, upsertedCount: 0 } testdb> db.rooms.find().pretty() [ { _id: ObjectId("63885aec72d61551eaf91e79"), name: '單人房', price: 1100, rating: 4.4 }, { _id: ObjectId("63885b6d72d61551eaf91e7a"), rating: 4.3, price: 1500, name: '豪華單人房' } ] ``` #### 刪除資料 刪除一筆資料 > deleteOne() ``` testdb> db.rooms.deleteOne({"name":"test nosql updateOne"}) { acknowledged: true, deletedCount: 1 } testdb> db.rooms.find().pretty() [ { _id: ObjectId("63885aec72d61551eaf91e79"), name: '單人房', price: 1000, rating: 4.5 }, { _id: ObjectId("63885b6d72d61551eaf91e7a"), rating: 4.3, price: 1500, name: '豪華單人房' }, { _id: ObjectId("63885b6d72d61551eaf91e7b"), rating: 4.8, price: 300, name: '雙人房' } ] ``` 刪除多筆資料 > deleteMany() ``` testdb> db.rooms.find() [ { _id: ObjectId("63885aec72d61551eaf91e79"), name: '單人房', price: 1000, rating: 4.5 }, { _id: ObjectId("63885b6d72d61551eaf91e7a"), rating: 4.3, price: 1500, name: '豪華單人房' }, { _id: ObjectId("63885b6d72d61551eaf91e7b"), rating: 4.8, price: 300, name: '雙人房' }, { _id: ObjectId("63886f092facbdf49a82817e"), name: '雙人房' } ] testdb> db.rooms.deleteMany({'name':'雙人房'}) { acknowledged: true, deletedCount: 2 } testdb> db.rooms.find() [ { _id: ObjectId("63885aec72d61551eaf91e79"), name: '單人房', price: 1000, rating: 4.5 }, { _id: ObjectId("63885b6d72d61551eaf91e7a"), rating: 4.3, price: 1500, name: '豪華單人房' } ] ``` #### 查詢資料 MongoDB 查詢資料的語法格式如下: * query:可選,使用查詢操作符指定查詢條件 * projection:可選,使用投影操作符指定返回的鍵。查詢時返回資料中所有鍵值, 只需省略該參數即可(默認省略)。 ``` db.collection.find(query, projection) ``` 如果你需要以易讀的方式來讀取數據,可以使用pretty() 方法,語法格式如下: ``` db.col.find().pretty() ``` 查詢資料 > find() ``` testdb> db.rooms.find().pretty() [ { _id: ObjectId("63885aec72d61551eaf91e79"), name: '單人房', price: 1100, rating: 4.4 }, { _id: ObjectId("63885b6d72d61551eaf91e7a"), rating: 4.3, price: 1500, name: '豪華單人房' } ] ``` 查詢一筆資料 > findOne() ``` testdb> db.rooms.findOne() { _id: ObjectId("63885aec72d61551eaf91e79"), name: '單人房', price: 1100, rating: 4.4 } ``` **MongoDB 與RDBMS Where 語句比較** MongoDB中條件操作符有: * (=) 等於 - $eq * (!=) 不等於 - $ne * (>) 大於 - $gt * (<) 小於 - $lt * (>=) 大於等於 - $gte * (<=) 小於等於 - $lte * (in) 存在某值 - $in * (not in) 不存在某值 - $nin 如果你熟悉常規的SQL 數據,通過下表可以更好的理解MongoDB 的條件語句查詢: | 操作 | 格式 | 範例 | RDBMS中的類似語句 | | -------- | -------- | -------- | -------- | | 等於 | {<key>:<value>}| db.col.find({"by":"菜鳥教程"}).pretty() | where by = '菜鳥教程'| |小於 |{<key>:{$lt:<value>}}| db.col.find({"likes":{$lt:50}}).pretty() |where likes < 50 | |小於或等於 |{<key>:{$lte:<value>}}| db.col.find({"likes":{$lte:50}}).pretty()| where likes <= 50 | |大於 |{<key>:{$gt:<value>}} |db.col.find({"likes":{$gt:50}}).pretty()| where likes > 50 | |大於或等於 |{<key>:{$gte:<value>}} |db.col.find({"likes":{$gte:50}}).pretty()| where likes >= 50 | |不等於 |{<key>:{$ne:<value>}}| db.col.find({"likes":{$ne:50}}).pretty()| where likes != 50 | **MongoDB AND 條件** MongoDB 的find() 方法可以傳入多個鍵(key),每個鍵(key)以逗號隔開,即常規SQL 的AND 條件。 語法格式如下: ``` db.col.find({key1:value1, key2:value2}).pretty() ``` 實例 ``` testdb> db.rooms.find({'name':'單人房','rating':4.4}) [ { _id: ObjectId("63885aec72d61551eaf91e79"), name: '單人房', price: 1100, rating: 4.4 } ] ``` **MongoDB OR 條件** MongoDB OR 條件語句使用了關鍵字$or ,語法格式如下: ``` db.col.find( { $or: [ {key1: value1}, {key2:value2} ] } ).pretty() ``` 實例 ``` testdb> db.rooms.find({$or:[{'name':'單人房'},{'rating':4.3}]}) [ { _id: ObjectId("63885aec72d61551eaf91e79"), name: '單人房', price: 1100, rating: 4.4 }, { _id: ObjectId("63885b6d72d61551eaf91e7a"), rating: 4.3, price: 1500, name: '豪華單人房' } ] ``` **AND 和OR 聯合使用** 以下實例演示了AND 和OR 聯合使用,類似常規SQL 語句為: 'where rating>4.3 AND (name = '單人房' OR price = 1100)' ``` testdb> db.rooms.find({'rating':{$gt:4.3},$or:[{'name':'單人房'},{'price':1100}]}) [ { _id: ObjectId("63885aec72d61551eaf91e79"), name: '單人房', price: 1100, rating: 4.4 } ] ``` 查詢小總結 ``` ## 一般搜尋 - db.集合名稱(collections name).find() - 尋找對應屬性:db.collections.find({屬性名稱:屬性值}) - 模糊搜尋:db.rooms.find({"name":/雙/}) - 數值區間:db.collections.find({屬性名稱:{$lte:400}}) - 複合條件:db.collections.find({屬性名稱:{$lte:400},rating:{$gte:4.8}}) ## 常用語法 - project 保護欄位:db.rooms.find({"name":/雙/},{"_id":0}) - 搜尋陣列裡面的值:db.rooms.find({"payment":{$in:["信用卡"]}}) ```