MongoDB
Table of Contents
1. MongoDB
1.1. playground
1.1.1. install mongodb
docker run --name mongodb -e MONGO_INITDB_ROOT_USERNAME=test -e MONGO_INITDB_ROOT_PASSWORD=test \ -e MONGO_INITDB_DATABASE=test_db -p 27017:27017 -d mongo:latest
1.1.2. use mongosh
mongosh --user test --password test
1.1.3. database and collection
# show databases test> show databases admin 100.00 KiB config 108.00 KiB local 72.00 KiB # db 命令显示当前的 db, 默认为 test test> db test # 使用 use 来切换或创建 db test> use test_db switched to db test_db # 显示 db 的 collections test_db> show collections # 首次插入数据同时会新建 collection 和 db test_db> db.test_collection.insertOne({title:"one"}) # collection 和 sql 的 table 类似, 但没有固定的 schema test_db> db.test_collection.insertOne({data:10}) # 删除 collection test_db> db.test_collection.drop() # 删除 db test_db> db.dropDatabase()
1.1.4. insert
# 插入数据 test_db> db.test_collection.insertOne({title:"one"}) # 插入多条 test_db> db.test_collection.insertMany([{title:"three"},{title:"four"}])
1.1.5. update
test_db> db.test_collection.updateOne({title:"one"}, {$set:{title:"oneone"}}) test_db> db.test_collection.updateMany({title:/one/}, {$set:{title:"oneone"}}) test_db> db.test_collection.replaceOne({title:"one"}, {title:"oneone"})
1.1.6. delete
test_db> db.test_collection.deleteOne({title:"one"}) { acknowledged: true, deletedCount: 0 } test_db> db.test_collection.deleteOne({title:/one/}) { acknowledged: true, deletedCount: 1 } test_db> db.test_collection.deleteMany({}) { acknowledged: true, deletedCount: 3 }
1.1.7. query
# 查询 collection 中的数据 test_db> db.test_collection.find() [ { _id: ObjectId("62862a228757e7065ce3bf8b"), title: 'one' } ] # 使用查询条件 test_db> db.test_collection.insertOne({title:"one"}) test_db> db.test_collection.find({title:"one"}) [ { _id: ObjectId("62862a228757e7065ce3bf8b"), title: 'one' } ] # 使用 regexp 查询 test_db> db.test_collection.find({title:/o/}) [ { _id: ObjectId("62862a228757e7065ce3bf8b"), title: 'one' }, { _id: ObjectId("62862a6a8757e7065ce3bf8c"), title: 'two' } ] test_db> db.test_collection.find({title:/.*e$/}) [ { _id: ObjectId("62862a228757e7065ce3bf8b"), title: 'one' } ] # 使用 query operator: and, or, not, lt, lte, eq, ne, gt test_db> db.test_collection.find({$or:[{title:"one"},{title:"two"}]}) [ { _id: ObjectId("62862a228757e7065ce3bf8b"), title: 'one' }, { _id: ObjectId("62862a6a8757e7065ce3bf8c"), title: 'two' } ] test_db> db.test_collection.find({title:{$not:{$eq:"one"}}}) test_db> db.test_collection.find({title:{$not:/one/}}) # in, nin test_db> db.test_collection.find({title:{$in:["one","two"]}}) [ { _id: ObjectId("6286379d3c9918cd8a68f2d7"), title: 'one' }, { _id: ObjectId("6286379d3c9918cd8a68f2d8"), title: 'two' } ] # exists, type, mod, regex # all, size
1.1.8. query sub-document
test_db> db.test_collection.insertMany( [ { item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" }, { item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "A" }, { item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" }, { item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" }, { item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" } ]); # 这里需要 size 的 `值` 完全相等 test_db> db.test_collection.find({size:{h:10,w:15.25,uom:"cm"}}) [ { _id: ObjectId("628639bd3c9918cd8a68f2de"), item: 'postcard', qty: 45, size: { h: 10, w: 15.25, uom: 'cm' }, status: 'A' } ] # 通过 a.b.c 匹配 sub-document 中的 field test_db> db.test_collection.find({"size.h":{$gt:10}}) [ { _id: ObjectId("628639bd3c9918cd8a68f2da"), item: 'journal', qty: 25, size: { h: 14, w: 21, uom: 'cm' }, status: 'A' }, { _id: ObjectId("628639bd3c9918cd8a68f2dd"), item: 'planner', qty: 75, size: { h: 22.85, w: 30, uom: 'cm' }, status: 'D' } ]
1.1.9. query array
test_db> db.test_collection.insertMany([ { item: "journal", qty: 25, tags: ["blank", "red"], dim_cm: [ 14, 21 ] }, { item: "notebook", qty: 50, tags: ["red", "blank"], dim_cm: [ 14, 21 ] }, { item: "paper", qty: 100, tags: ["red", "blank", "plain"], dim_cm: [ 14, 21 ] }, { item: "planner", qty: 75, tags: ["blank", "red"], dim_cm: [ 22.85, 30 ] }, { item: "postcard", qty: 45, tags: ["blue"], dim_cm: [ 10, 15.25 ] } ]); # array 做为整体来比较 test_db> test_db> db.test_collection.find({tags:["red", "blank"]}) [ { _id: ObjectId("628649603c9918cd8a68f2e0"), item: 'notebook', qty: 50, tags: [ 'red', 'blank' ], dim_cm: [ 14, 21 ] } ] # 顺序无关的比较 test_db> db.test_collection.find({tags:{$all:["blank","red"]}}) # array 中存在一个 item 为 blank test_db> db.test_collection.find({tags:"blank"}) # dim_cm 中存在一个 item 大于 25 test_db> db.test_collection.find( { dim_cm: { $gt: 25 } } ) # dim_cm 中存在一个 item_a 大于 12, 且存在一个 item_b 小于 9, # item_a 可以与 item_b 不同 test_db> db.test_collection.find( { dim_cm: { $gt: 12, $lt: 9 } } ) # dim_cm 中存一个 item 大于 22 且小于 30 test_db> db.test_collection.find( { dim_cm: { $elemMatch: { $gt: 22, $lt: 30 } } } ) # 用 xx.0 访问 array 的第一个 item test_db> db.test_collection.find( { "dim_cm.1": { $gt: 25 } } ) # 匹配 array 的长度 test_db> db.test_collection.find( { "tags": { $size: 3 } } )
1.1.10. query projection
test_db> db.test_collection.find( { dim_cm: { $gt: 12} }, {qty:1} ) [ { _id: ObjectId("628649603c9918cd8a68f2df"), qty: 25 }, { _id: ObjectId("628649603c9918cd8a68f2e0"), qty: 50 }, { _id: ObjectId("628649603c9918cd8a68f2e1"), qty: 100 }, { _id: ObjectId("628649603c9918cd8a68f2e2"), qty: 75 }, { _id: ObjectId("628649603c9918cd8a68f2e3"), qty: 45 } ] test_db> db.test_collection.find( { dim_cm: { $gt: 12} }, {qty:0,item:0,dim_cm:0,_id:0} ) [ { tags: [ 'blank', 'red' ] }, { tags: [ 'red', 'blank' ] }, { tags: [ 'red', 'blank', 'plain' ] }, { tags: [ 'blank', 'red' ] }, { tags: [ 'blue' ] } ]
1.1.11. aggregation
1.2. go binding
https://www.mongodb.com/docs/drivers/go/v1.9/
mongodb-compass 应用有一个 `export to language` 功能可以把 mongosh 的语句转换成不同语言的 binding
1.3. replica set
1.4. shard
1.5. index
equality -> sort -> range
1.6. profiling
- explain
- setProfileLevel
1.7. 坑
- count 操作 (包括 DocumentCount 和 count aggregation) 非常慢, 即使有 index 也需要 scan
- skip 非常慢, 因为它通过 `从头 scan` 有方式来 skip…, 所以通过 skip+limit 来实现 paging 不可行