一,mongo的增删改查

假设有一份商品结构的表

{
    "id":"r24EIHYBZCX0L6qWIrDf",
    "name":"product-1",
    "price":123,
    "detail":"<html><body>hello world</body></html>",
    "sku":[
        {
            "id":"r14EIHYBZCX0L6qWIrDf",
            "inventory":123
        }
    ],
    "tag":[
        "red",
        "black"
    ]
}

1.1 插入数据

db.collection.insertOne()插入单条数据,其中collection是变量,代表你希望往哪个集合插入数据。

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(),插入多条数据,需要传插入文档的数组

db.product.insertMany([
{
    "id":"r24EIHYBZCX016qWIrDf",
    "name":"product-2",
    ...//省略
},{
    "id":"r24EIHYBZC40L6qWIrDf",
    "name":"product-3",
    ...
}])

//返回
{
    "acknowledged" : true,
    "insertedIds" : [
        ObjectId("5ffa6bc39bb4925656ccad86"),
        ObjectId("5ffa6bc39bb4925656ccad87")
    ]
}

更多插入方式

1.2 查找数据

db.collection.findOne(query, projection),其中query与projection都是json文档类型

1.2.1简单查询

简单的数据匹配,只需要query按{ <field1>: <value1>, ... }格式去写就可以了,多个field是and条件

//查询一条字段“name”为"product-1"的数据
db.product.findOne({
  "name":"product-1"
})

//查询一条字段“name”为"product-1"且"price"为123的数据
db.product.findOne({
  "name":"product-1",
  "price":123
})
1.2.2 或查询

$in操作符,格式:{ field: { $in: [<value1>, <value2>, ... <valueN> ] } },可以查找同一个字段的多个值条件,当数组中只有一个值时,相当于=

//查找price为100,200,300的数据
db.product.find({
  "price":{
    "$in":[100,200,300]
  }
})

$or操作符,格式:{ $or: [ { <expression1> }, { <expression2> }, ... , { <expressionN> } ] },expression为查询表达式

//查询要么price为100或者name为“product-1"的数据
db.product.find({
  "$or":[
    {"price":100},
    {"name":"product-1"}
  ]
})

$in,$or区别主要有:
1,$in作用于具体的一个字段,$or作用于多个expression
2,$in只需要执行一次搜索,$or根据expression的数量执行多个搜索,然后合并,会更耗性能
3,$in实际上是一种范围比较查询

1.2.3 数组查询
1.2.3.1 $all查询

mongo中数组查询相对比较特殊,假设表中有3条数据,第一条与第二条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 ]
}])

如果我们按前面说的查询方式查找下数据

db.product.find( { tags: ["red", "blank"] } )

这样只会返回第一条记录,第二条记录不会返回。这种方式的查询需要数据里面的值与顺序都匹配才认为是符合查询条件的,那如果我只需要查找数组里面的值匹配,不关心存放顺序,那么就要按下面的这种方式查询

db.product.find( { tags: { $all: ["red", "blank"] } } )
1.2.3.2 数组范围查询

如果我们想要查找dim_cm大于15小于20的数据,想当然会这样子写:

db.product.find( { dim_cm: { $gt: 15, $lt: 20 } } )

你会发现查回来的数据包含了dim_cm: [ 10, 15.25 ]这条数据,实际上这样搜索,查找时mongo用15.25满足$gt: 1510满足$lt: 20条件,得到了错误的查询结果,正确的查询方式需要用到$elemMatch操作符

db.inventory.find( { dim_cm: { $elemMatch: { $gt: 15, $lt: 20 } } } )

至于为什么会这样子,估计是mongo把数组里面的元素当做一个整体看待,只要整体满足条件即可,不需要每个元素满足所有条件

1.2.4 projection

很多时候我们并不想要把文档中的所有字段返回回来,例如商品表中的detail字段,一般都比较大,多个商品查询也返回时会对网络io及服务器内存分配都造成不必要的压力,这时候我们就需要用到projection

例如我们不返回商品detail,以及mongo自带的_id

db.product.find({},{"_id":0,"detail":0})

1.3 更新数据

常见的更新方法:
db.collection.updateOne()
db.collection.updateMany()
db.collection.replaceOne()
个人感觉db.collection.replaceOne是覆盖原有文档,实际上update的操作也能做到,但是replaceOne只允许覆盖操作,不能带有update operators expressions,另外从功能语义上update不要做覆盖操作

例如我想把name为"product-1"的数据的price改成200,需要用到$set操作符

db.product.updateOne({"name":"product-1"},{"$set":{"price":200}})

如果我们没有使用$set操作符,相当于覆盖

/*
会将
{
"id":***,
"name":"product-1",
....
}文档变成
{
"price":200
}
*/
db.product.updateOne({"name":"product-1"},{"price":200})

$set更新或创建文档field,语法:{ $set: { <field1>: <value1>, ... } }

$unset 删除文档field,语法:{ $unset: { <field1>: "", ... } }

1.4 删除数据

常见的更新方法:
db.collection.deleteOne()
db.collection.deleteMany()
db.collection.remove()
remove与delete最大的区别在于delete会返回acknowledged字段
db.collection.deleteMany({})会删除所有数据,时间要根据数据量,更快的删除考虑用db.collection.drop(),会删掉整个集合数据包括集合本身信息如index
更多方式删除

1.5 特殊场景操作

1.5.1 update参数upsert作用

update的完整参数如下:

db.collection.updateOne(
   <filter>,
   <update>,
   {
     upsert: <boolean>,
     writeConcern: <document>,
     collation: <document>,
     arrayFilters: [ <filterdocument1>, ... ],
     hint:  <document|string>        // Available starting in MongoDB 4.2.1
   }
)

upsert的含义,数据表中能查到就更新,没有就插入,例如下面这个场景:
假如有个页面统计次数的功能

// 检查这个页面是否有一个文档 
blog = db.analytics.findOne({url : "/blog"}) // 如果有,就将视图数加/并保存 
if (blog) { 
    blog.pageviews++; db.analytics.save(blog); 
}
// 否则为这个页面创建一个新文档 
else {
    db.analytics.save({url : "/blog", pageviews : 1}) 
}

这种写法有2个问题:1,复杂,2,多线程会存在竞态条件
采用upsert可以解决这2个问题

db.analytics.update({"url" : "/blog"}, {"$inc" : {"pageviews" : 1}}, true)
1.5.2 findAndModify

db.collection.findAndModify这个方法的作用是修改符合条件的文档,并将文档修改前的数据返回回来,这对于操作队列以及执行其他需要进行原子性取 值和赋值的操作来说,十分方便。
例如存在队列结构


{ "_id" : ObjectId(), "status" : state, "priority" : N }

/*
将任务按优先级排列,并将排在第一个的状态修改为RUNNING,
返回的数据可以认为被当前线程独占了,后续操作不会发生竞争关系了
*/
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"}})
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容