假設(shè)有一份商品結(jié)構(gòu)的表
{
"id":"r24EIHYBZCX0L6qWIrDf",
"name":"product-1",
"price":123,
"detail":"<html><body>hello world</body></html>",
"sku":[
{
"id":"r14EIHYBZCX0L6qWIrDf",
"inventory":123
}
],
"tag":[
"red",
"black"
]
}
1.1 插入數(shù)據(jù)
db.collection.insertOne()插入單條數(shù)據(jù)悉尾,其中collection是變量突那,代表你希望往哪個集合插入數(shù)據(jù)。
db.product.insertOne(
{
"id":"r24EIHYBZCX0L6qWIrDf",
"name":"product-1",
"price":123,
"detail":"<html><body>hello world</body></html>",
"sku":[
{
"id":"r14EIHYBZCX0L6qWIrDf",
"inventory":123
}
],
"tag":[
"red",
"black"
]
})
//返回
{
"acknowledged" : true,
"insertedId" : ObjectId("5ffa68feda5b1dccc637c4a9")
}
db.collection.insertMany(),插入多條數(shù)據(jù)构眯,需要傳插入文檔的數(shù)組
db.product.insertMany([
{
"id":"r24EIHYBZCX016qWIrDf",
"name":"product-2",
...//省略
},{
"id":"r24EIHYBZC40L6qWIrDf",
"name":"product-3",
...
}])
//返回
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("5ffa6bc39bb4925656ccad86"),
ObjectId("5ffa6bc39bb4925656ccad87")
]
}
1.2 查找數(shù)據(jù)
db.collection.findOne(query, projection),其中query與projection都是json文檔類型
1.2.1簡單查詢
簡單的數(shù)據(jù)匹配愕难,只需要query按{ <field1>: <value1>, ... }格式去寫就可以了,多個field是and條件
//查詢一條字段“name”為"product-1"的數(shù)據(jù)
db.product.findOne({
"name":"product-1"
})
//查詢一條字段“name”為"product-1"且"price"為123的數(shù)據(jù)
db.product.findOne({
"name":"product-1",
"price":123
})
1.2.2 或查詢
$in
操作符惫霸,格式:{ field: { $in: [<value1>, <value2>, ... <valueN> ] } }猫缭,可以查找同一個字段的多個值條件,當(dāng)數(shù)組中只有一個值時壹店,相當(dāng)于=
//查找price為100猜丹,200,300的數(shù)據(jù)
db.product.find({
"price":{
"$in":[100,200,300]
}
})
$or
操作符硅卢,格式:{ $or: [ { <expression1> }, { <expression2> }, ... , { <expressionN> } ] }射窒,expression為查詢表達(dá)式
//查詢要么price為100或者name為“product-1"的數(shù)據(jù)
db.product.find({
"$or":[
{"price":100},
{"name":"product-1"}
]
})
$in
,$or
區(qū)別主要有:
1,$in
作用于具體的一個字段,$or
作用于多個expression
2将塑,$in
只需要執(zhí)行一次搜索脉顿,$or
根據(jù)expression的數(shù)量執(zhí)行多個搜索,然后合并点寥,會更耗性能
3艾疟,$in
實(shí)際上是一種范圍比較查詢
1.2.3 數(shù)組查詢
1.2.3.1 $all
查詢
mongo中數(shù)組查詢相對比較特殊,假設(shè)表中有3條數(shù)據(jù)敢辩,第一條與第二條tag值一樣蔽莱,但順序不一樣
db.product.insertMany([
{
...
"tag":[
"red",
"black"
],
dim_cm: [ 14, 21 ]
},{
...
"tag":[
"black",
"red"
],
dim_cm: [ 22.85, 30 ]
},{
...
"tag":[
"yellow",
"red"
],
dim_cm: [ 10, 15.25 ]
}])
如果我們按前面說的查詢方式查找下數(shù)據(jù)
db.product.find( { tags: ["red", "blank"] } )
這樣只會返回第一條記錄,第二條記錄不會返回戚长。這種方式的查詢需要數(shù)據(jù)里面的值與順序都匹配才認(rèn)為是符合查詢條件的盗冷,那如果我只需要查找數(shù)組里面的值匹配,不關(guān)心存放順序历葛,那么就要按下面的這種方式查詢
db.product.find( { tags: { $all: ["red", "blank"] } } )
1.2.3.2 數(shù)組范圍查詢
如果我們想要查找dim_cm大于15小于20的數(shù)據(jù)正塌,想當(dāng)然會這樣子寫:
db.product.find( { dim_cm: { $gt: 15, $lt: 20 } } )
你會發(fā)現(xiàn)查回來的數(shù)據(jù)包含了dim_cm: [ 10, 15.25 ]
這條數(shù)據(jù),實(shí)際上這樣搜索恤溶,查找時mongo用15.25
滿足$gt: 15
而10
滿足$lt: 20
條件乓诽,得到了錯誤的查詢結(jié)果,正確的查詢方式需要用到$elemMatch
操作符
db.inventory.find( { dim_cm: { $elemMatch: { $gt: 15, $lt: 20 } } } )
至于為什么會這樣子咒程,估計(jì)是mongo把數(shù)組里面的元素當(dāng)做一個整體看待鸠天,只要整體滿足條件即可,不需要每個元素滿足所有條件
1.2.4 projection
很多時候我們并不想要把文檔中的所有字段返回回來帐姻,例如商品表中的detail字段稠集,一般都比較大奶段,多個商品查詢也返回時會對網(wǎng)絡(luò)io及服務(wù)器內(nèi)存分配都造成不必要的壓力,這時候我們就需要用到projection
例如我們不返回商品detail剥纷,以及mongo自帶的_id
db.product.find({},{"_id":0,"detail":0})
1.3 更新數(shù)據(jù)
常見的更新方法:
db.collection.updateOne()
db.collection.updateMany()
db.collection.replaceOne()
個人感覺db.collection.replaceOne是覆蓋原有文檔痹籍,實(shí)際上update的操作也能做到,但是replaceOne只允許覆蓋操作晦鞋,不能帶有update operators expressions蹲缠,另外從功能語義上update不要做覆蓋操作
例如我想把name為"product-1"的數(shù)據(jù)的price改成200,需要用到$set
操作符
db.product.updateOne({"name":"product-1"},{"$set":{"price":200}})
如果我們沒有使用$set
操作符,相當(dāng)于覆蓋
/*
會將
{
"id":***,
"name":"product-1",
....
}文檔變成
{
"price":200
}
*/
db.product.updateOne({"name":"product-1"},{"price":200})
$set
更新或創(chuàng)建文檔field,語法:{ $set: { <field1>: <value1>, ... } }
$unset
刪除文檔field,語法:{ $unset: { <field1>: "", ... } }
1.4 刪除數(shù)據(jù)
常見的更新方法:
db.collection.deleteOne()
db.collection.deleteMany()
db.collection.remove()
remove與delete最大的區(qū)別在于delete會返回acknowledged字段
db.collection.deleteMany({})
會刪除所有數(shù)據(jù)悠垛,時間要根據(jù)數(shù)據(jù)量线定,更快的刪除考慮用db.collection.drop()
,會刪掉整個集合數(shù)據(jù)包括集合本身信息如index
更多方式刪除
1.5 特殊場景操作
1.5.1 update參數(shù)upsert作用
update的完整參數(shù)如下:
db.collection.updateOne(
<filter>,
<update>,
{
upsert: <boolean>,
writeConcern: <document>,
collation: <document>,
arrayFilters: [ <filterdocument1>, ... ],
hint: <document|string> // Available starting in MongoDB 4.2.1
}
)
upsert的含義确买,數(shù)據(jù)表中能查到就更新斤讥,沒有就插入,例如下面這個場景:
假如有個頁面統(tǒng)計(jì)次數(shù)的功能
// 檢查這個頁面是否有一個文檔
blog = db.analytics.findOne({url : "/blog"}) // 如果有湾趾,就將視圖數(shù)加/并保存
if (blog) {
blog.pageviews++; db.analytics.save(blog);
}
// 否則為這個頁面創(chuàng)建一個新文檔
else {
db.analytics.save({url : "/blog", pageviews : 1})
}
這種寫法有2個問題:1芭商,復(fù)雜,2撑帖,多線程會存在競態(tài)條件
采用upsert可以解決這2個問題
db.analytics.update({"url" : "/blog"}, {"$inc" : {"pageviews" : 1}}, true)
1.5.2 findAndModify
db.collection.findAndModify
這個方法的作用是修改符合條件的文檔蓉坎,并將文檔修改前的數(shù)據(jù)返回回來,這對于操作隊(duì)列以及執(zhí)行其他需要進(jìn)行原子性取 值和賦值的操作來說胡嘿,十分方便蛉艾。
例如存在隊(duì)列結(jié)構(gòu)
{ "_id" : ObjectId(), "status" : state, "priority" : N }
/*
將任務(wù)按優(yōu)先級排列,并將排在第一個的狀態(tài)修改為RUNNING,
返回的數(shù)據(jù)可以認(rèn)為被當(dāng)前線程獨(dú)占了衷敌,后續(xù)操作不會發(fā)生競爭關(guān)系了
*/
ps = db.runCommand({
"findAndModify" : "processes",
"query" : {"status" : "READY"},
"sort" : {"priority" : -1},
"update" : {"$set" : {"status" : "RUNNING"}}}).value
do_something(ps)
db.process.update({"_id" : ps._id}, {"$set" : {"status" : "DONE"}})