MongoDB实践一 (安装&CURD)

存储文档的非关系型数据库
 
MongoDB之安装与使用
 
MongoDB的安装与配置
docker run --name mymongo -v /mymongo/data:/data/db -d mongo:latest
--name mymongo:自定义容器的名字
-v /mymongo/data:/data/db:挂载数据目录,使得数据可以在本地查看,不会在docker关闭之后丢失
-d:后台运行容器
 
mongo-express的安装与配置
docker run --link mymongo:mongo -p 8081:8081 mongo-express
--link mymongo:mongo:使得该容器与另一个容器相关联
-p 8081:8081:使得容器的端口暴露,可以被外界访问
 
docker stop mymongo
docker start mymongo
 
交互访问容器
docker exec -it mymongo mongo
 
 
MongoDB 之 Create
 
  1. 创建一个文档
    1. db.<collection>.insertOne(<document>,{writeConcern:<documnet>})
    2. writeConcern:定义了安全写级别,安全级别用于判断一次写是否成功,同时安全级别越高,丢失数据的风险越低,写入操作的延迟也越高,不提供的话mongoDB使用默认的安全写级别。
    3. db.accounts.insertOne( {_id:"account1",name:"alice",balance:100})
    4. { "acknowledged" : true, "insertedId" : "account1" }
 
  1. 创建多个文档
    1. db.<collection>.insertMany( [<document1>,<document2>,...],{ writeConcern:<document>,ordered:<boolean> })
    2. db.accounts.insertMany([ { name:"charlie", balance:500 }, { name:"david", balance:200 } ] );
    3. ordered:用于决定mongoDB是否按顺序来写入文档,定义为true(默认值)时会严格按照我们提供的顺序写入文档,一旦遇到错误操作会退出,剩余文档不会写入数据库,当定义为false时,剩余的正确文档会被写入。
 
  1. 创建单个或多个文档
    1. db.<collection>.insert(<document or array of documents>, {writeConcern:<document>,ordered:<boolean> })
    2. try{ db.accounts.insert({_id:"account10",name:"alice",balance:100}) }catch(e){print(e); };
    3. 区别:只有insert支持db.collection.explain()命令
 
  1. 更新文档
    1. try{ db.accounts.save({_id:"account2",name:"alice",balance:100}) }catch(e){print(e); };
    2. 处理一个新文档的时候,它会调用insertOne()命令
 
  1. 复合文档
    1. db.accounts.insert({ _id:{type:"saving",accountNo:"1"}, name:"tom", balance:600})
    2. WriteResult({ "nInserted" : 1 })
    3. 当使用文档作为文档主键的时候,用作主键的文档字段顺序不同,创建时不会报错
 
  1. ObjectId() 对象主键
 
  1. ObjectId().getTimestamp();
 
 
MongoDB 之 Read
 
  1. 读取文档
    1. db.<collection>.find();
 
  1. 匹配查询
    1. db.<collection>.find(<query>,<projection>)
    2. <query>定义了读取操作时筛选文档的条件
    3. <projection>定义了对读取结果进行的投射操作
    4. db.accounts.find({name:"alice"}) { "_id" : "account1", "name" : "alice", "balance" : 100 }
    5. 复合主键的匹配查询 db.accounts.find({"_id.type":"saving"})
 
  1. 查询操作符
 
    1. 比较操作符
      1. {<field>:{$<operator>:<value>}}
      2. <operator>:
        1. $eq(匹配与字段相等的文档),
          1. db.accounts.find( {name:{$eq:"tom"}} );
        2. $ne (匹配与字段不等的文档),
          1. ps:会筛选出不包含查询字段的文档!!!就是说有文档并没有这个字段也能被筛选出来。
          2. db.accounts.find( {type:{$ne:"saving"}} );
        3. $gt,匹配字段值大于查询值的文档,
        4. $gte,匹配字段值大于或等于查询值的文档,
        5. $lt,匹配字段小于查询值的文档,
        6. $lte,匹配字段小于或等于查询值的文档,
        7. $in  匹配字段值与任一查询值相等的文档,ps:传入字段是数组
          1. db.accounts.find({"name":{$in:["charlie"]}})
        8. $nin  匹配字段值与任何查询值都不等的文档,
          1. 需要注意的是,和$ne一样,$nin也会筛选出并不包含查询字段的文档!!!
 
    1. 逻辑操作符
      1. $not  筛选条件不成立的文档
        1. {field:{$not:{<operator-expression>}},$not也和$ne一样同样会筛选出不包含查询字段的文档
        2. db.accounts.find({"balance":{$not:{$lt:500}}})
 
    1. $and  匹配多个筛选条件全部成立的文档
      1. {$and:[{<expression1>},{<expression2>},...]}
      2. 全写 db.accounts.find({$and:[{"balance":{$gt:100}} , {"name":{$gt:"fred"}}]})
      3. 简写
        1. db.accounts.find({balance:{$gt:100},name:{$gt:"fred"}})
        2. db.accounts.find({balance:{$gt:100,$lt:500}})
    2. $or  匹配至少一个筛选条件成立的文档
      1. db.accounts.find({$or:[{"name":{$eq:"david"}},{"balance":{$eq:200}}]})
 
    1. $nor 匹配筛选条件全都不成立的文档,
      1. 需要注意的是,和$ne一样,$nor也会筛选出并不包含查询字段的文档
      2. db.accounts.find({$nor:[{name:"alice"},{name:"charlie"},{balance:{$lt:100}}]});
 
    1. 字段操作符
      1. $exists 匹配包含查询字段的文档
        1. {field:{$exists:<boolean>}
        2. db.accounts.find({$nor:[{"_id.type":{$exists:true}}]})
        3. db.accounts.find({"_id.type":{$ne:"checking",$exists:true}});
 
    1. type $type  匹配字段类型复合查询值的文档
      1. {field:{$type:<BSON type>}}
      2. db.accounts.find({_id:{$type:["object"]}})
      3. {field:{$type:[<BSON type1>,<BSON type2>,...]}}
      4. db.accounts.find({_id:{$type:["objectId","object"]}})
 
    1. 数组操作符
      1. db.accounts.find({ contact:{$all:[ {$elemMatch:{$gt:"10000000",$lt:"20000000"}}, {$elemMatch:{$gt:"20000000",$lt:"30000000"}} ]}});
      2. $all  匹配数组字段中包含所有查询值的文档
        1. {field:{$all:[<value1>,<value2>,...]}}
        2. db.accounts.find({contact:{$all:[["2222222","3333333"]]}})
 
    1. $elemMatch  匹配数组字段中至少存在一个值满足筛选条件的文档
      1. {field:{$elemMatch:{<query1>,<query2>,...}}}
      2. db.accounts.find({ contact: {$elemMatch:{$gt:"10000000",$lt:"22222222222222222222"}}});
 
 
    1. 运算操作符
      1. $regex  匹配满足正则表达式的文档
        1. {field:{:/pattern/,:'<options>'}}
          1. db.accounts.find({name:{$regex:/LIE/,$options:'i'}})
        2. {field:{:/pattern/<options>}},在和$in操作符一起使用时,只能使用该语法
          1. db.accounts.find({name:{$in:[/^c/,/^j/]}})
 
    1. db.collection.find()返回一个文档集合游标,在不迭代游标的情况下,只列出前20个文档
      1. 遍历完游标中所有的文档之后,或者在10分钟之后,游标便会自动关闭。
      2. db.accounts.find().noCursorTimeout(); ,使用noCursorTimeout() 函数来保持游标一直有效。
      3. var myCursor = db.accounts.find()
      4. myCursor.next();
      5. myCursor.hasNext();
      6. myCursor.forEach(printjson);
      7. db.accounts.find({name:"jack"}).skip(2); 跳过2个
      8. db.accounts.find({name:"jack"}).limit(1);
      9. db.accounts.find({name:"jack"}).count();
        1. db.accounts.find({name:"jack"}).limit(1).count(true); 为false,即cursor.count()不会考虑cursor.skip()和cursor.limit()的效果。
      10. db.accounts.find().sort({balance:-1,name:1}); 1表示正向排序,-1表示逆向排序
    2. *** 游标函数执行顺序 cursor.sort(),cursor.skip() , cursor.limit() , !!!
 
    1. 文档投影 db.collection.find(<query>,<projection>)
      1. 不使用投影时,返回符合筛选条件的完整文档。
      2. 使用投影可以选择性的返回文档中的部分字段
      3. db.accounts.find({},{contact:1}) 默认返回主键_id
      4. db.accounts.find({},{contact:2,_id:0}) 设置不返回主键_id
      5. db.accounts.find({},{name:0,_id:0,balance:1}) 除了文档主键_id,投影文档不允许混合使用包含和不包含
      6. 在数组字段上使用投影
        1. $slice操作符可以返回 数组字段中的部分元素
        2. 当$slice的参数为n时,表示投射数组中前n个元素 db.accounts.find({},{ name:1,contact:{$slice:1}})
        3. 当$slice的参数为-n时,表示投射数组中倒数n个元素 db.accounts.find({},{ name:1,contact:{$slice:-1}})
        4. 当$slice的参数为[n,m]时,表示数组进行skip(1)和limit(m)操作 db.accounts.find({},{ name:1,contact:{$slice:[1,2]}})
      7. $elemMatch和$操作符可以返回数组字段中满足筛选条件的第一个元素,当对文档的筛选条件和在投射操作中对数组的筛选条件一致的时候,可以使用$操作符
        1. db.accounts.find({},{ name:1,contact:{$elemMatch:{$gt:"Alabama"}}}) 额外使用一个筛选条件
        2. db.accounts.find({contact:{$eq:"Alabama"}},{_id:0,name:1,"contact.$":1}) 使用的是find筛选条件里的
 
    1. 左边是mongodb查询语句,右边是sql语句。对照着用,挺方便。
      1. db.users.find() select * from users
      2. db.users.find({"age" : 27}) select * from users where age = 27
      3. db.users.find({"username" : "joe", "age" : 27}) select * from users where "username" = "joe" and age = 27
      4. db.users.find({}, {"username" : 1, "email" : 1}) select username, email from users
      5. db.users.find({}, {"username" : 1, "_id" : 0}) // no case // 即时加上了列筛选,_id也会返回;必须显式的阻止_id返回
      6. db.users.find({"age" : {"$gte" : 18, "$lte" : 30}}) select * from users where age >=18 and age <= 30 // $lt(<) $lte(<=) $gt(>) $gte(>=)
      7. db.users.find({"username" : {"$ne" : "joe"}}) select * from users where username <> "joe"
      8. db.users.find({"ticket_no" : {"$in" : [725, 542, 390]}}) select * from users where ticket_no in (725, 542, 390)
      9. db.users.find({"ticket_no" : {"$nin" : [725, 542, 390]}}) select * from users where ticket_no not in (725, 542, 390)
      10. db.users.find({"$or" : [{"ticket_no" : 725}, {"winner" : true}]}) select * form users where ticket_no = 725 or winner = true
      11. db.users.find({"id_num" : {"$mod" : [5, 1]}}) select * from users where (id_num mod 5) = 1
      12. db.users.find({"$not": {"age" : 27}}) select * from users where not (age = 27)
      13. db.users.find({"username" : {"$in" : [null], "$exists" : true}}) select * from users where username is null // 如果直接通过find({"username" : null})进行查询,那么连带"没有username"的纪录一并筛选出来
      14. db.users.find({"name" : /joey?/i}) // 正则查询,value是符合PCRE的表达式
      15. db.food.find({fruit : {$all : ["apple", "banana"]}}) // 对数组的查询, 字段fruit中,既包含"apple",又包含"banana"的纪录
      16. db.food.find({"fruit.2" : "peach"}) // 对数组的查询, 字段fruit中,第3个(从0开始)元素是peach的纪录
      17. db.food.find({"fruit" : {"$size" : 3}}) // 对数组的查询, 查询数组元素个数是3的记录,$size前面无法和其他的操作符复合使用
      18. db.users.findOne(criteria, {"comments" : {"$slice" : 10}}) // 对数组的查询,只返回数组comments中的前十条,还可以{"$slice" : -10}, {"$slice" : [23, 10]}; 分别返回最后10条,和中间10条
      19. db.people.find({"name.first" : "Joe", "name.last" : "Schmoe"}) // 嵌套查询
      20. db.blog.find({"comments" : {"$elemMatch" : {"author" : "joe", "score" : {"$gte" : 5}}}}) // 嵌套查询,仅当嵌套的元素是数组时使用,
      21. db.foo.find({"$where" : "this.x + this.y == 10"}) // 复杂的查询,$where当然是非常方便的,但效率低下。对于复杂查询,考虑的顺序应当是 正则 -> MapReduce -> $where
      22. db.foo.find({"$where" : "function() { return this.x + this.y == 10; }"}) // $where可以支持javascript函数作为查询条件
      23. db.foo.find().sort({"x" : 1}).limit(1).skip(10); // 返回第(10, 11]条,按"x"进行排序; 三个limit的顺序是任意的,应该尽量避免skip中使用large-number
 
MongoDB 之 UPDATE
 
  1. db.collection.update()
    1. db.accounts.update({name:"leon"},{name:"leon",balance:200})
    2. 如果有多条文档,使用update默认只更新第一条
 
  1. db.<collection>.update(<query>,<update>,<options>)
 
  1. 更新特定字段
 
    1. $set 新增字段
      1. db.accounts.update({name:"leon"},{$set:{"info.dateOpened":new Date("2016-01-11T16:00:00Z")}})
      2. db.accounts.update({name:"leon"},{$set:{"info.balanch.liubi.0":[2,3,4]}}) .0更新指定数组元素
 
    1. $unset 删除字段
      1. db.accounts.update({name:"leon"},{$unset:{"info.balanch":""}})
      2. db.accounts.update({_id:ObjectId("5dd0f1e5062477b5f487f828")},{$unset:{"contact.0":""}}) 删除数组元素,数组元素的长度不会改变值为null
 
    1. $rename 重命名字段
      1. { $rename: { <fields1>: <newName1>,<field2>:<newName2>,...}}
      2. 如果rename命令要重命名得字段并不存在,那么文档内容不会被改变。
      3. db.accounts.update( {name:"leon"}, {$rename:{ "name":"name1" } });
      4. 如果新得字段名已经存在,那么原有得这个字段内容会被覆盖。
        1. 当$rename命令中得新字段存在得时候,$rename命令会先$unset新旧字段,然后再$set新字段。
      5. db.accounts.update({name:"karen"},{$rename:{"info.branch":"branch","balance":"info.balance"}});
      6. $rename 命令新旧字段均不可以指向数组元素。
 
    1. 更新操作符
      1. { $inc : { <field1> : <amount1>,...}}
        1. db.accounts.update({name:"david"},{$inc:{balance:-0.5}}) balance值-0.5
 
    1. { $mul: { <field1> : <number1>,..}}
      1. db.accounts.update({name:"david"},{$mul:{balance:2}}); balance值*2
      2. 只能应用在数字上
      3. 如果被更新得字段不存在 $inc会创建字段,并将字段值设为命令中得增减值,而$mul会创建字段,但是会把字段值设为0.
 
    1. { $min:{<field1>:<value1>, ...}}
      1. db.accounts.update({name:"karen"},{$min:{"info.balance":5000}});
      2. 与原来得balance进行比较,谁小取谁。
      3. db.accounts.update({name:"karen"},{$min:{"info.dateOpene":ISODate("2013-10-01T16:00:00Z")}})
      4. 可以比较时间
 
    1. { $max:{ <field1>:<value1>, ...}}
      1. db.accounts.update({name:"karen"},{$max:{"info.balance":5000}});
      2. 与原来得balance进行比较,谁大取谁。
      3. 如果被更新得字段不存在,$min和$max命令会创建字段,并且将字段值设为命令中得更新值。
      4. 如果被更新得字段类型与更新值类型不一致,$min和$max命令会按照BSON数据类型排序规则进行比较。
      5. 排序规则:
        1. 最小:Null,
          1. Numbers(ints, longs, doubles, decimals)
          2. Symbol,String,
          3. Object,
          4. Array,,
          5. BinData,
          6. Boolean,
          7. Date,
          8. Timestamp
        2. 最大:Regular Expression
 
    1. $addToSet 数组中添加字段
      1. db.accounts.update({name:"karen"},{$addToSet:{contact:"China"}})
      2. 如果添加得新值已经存在于数组中,则不会重复插入。
      3. db.accounts.update({name:"karen3"},{$addToSet:{contact:{primaryEmail:"xxx@gmail.com",secindaryEmail:"yyy@gamil.com"}}})
      4. db.accounts.update({name:"karen3"},{$addToSet:{contact:["contact1","contact2"]}})
      5. db.accounts.update({name:"karen3"},{$addToSet:{contact:{$each:["contact1","contact2"]}}})
 
    1. $pop
      1. db.accounts.update({name:"karen3"},{$pop:{"contact.3":-1}}) 删除内嵌数组第一个元素
 
    1. {$pull: {<fields1>:<value|condition>,...}} 删除特定元素
      1. db.accounts.update({name:"lawrence"},{$pull:{contact:{"primaryEmail":"xxx@gamil.com"}}})
      2. db.accounts.update({name:"karen"},{$pull:{contact:{$regex:/be/}}}) 删除 contact数组中包含 be得元素
      3. db.accounts.update({name:"karen"},{$pull:{contact:{$elemMatch:{$eq:"2222222"}}}}) 删除contact数组中,数组元素包含 222222得元素
      4. db.accounts.update({name:"lawrence"},{$pull:{contact:{"secindaryEmail":"yyy@gamil.com","primaryEmail":"xxx@gamil.com"}}})
      5. db.accounts.update({name:"lawrence"},{$pull:{contact:{"primaryEmail":"xxx@gamil.com"}}})
        1. pull 命令删除只要和原文档能匹配就能删。。。
 
    1. 复制文档 db.accounts.find({name:"karen3"},{_id:0}).forEach(function(doc){var newDoc = doc;newDoc.name="lawrence";db.accounts.insert(newDoc)})
 
    1. {$pullAll:{<field1>:[ <value1>,<value2>...].,..}} 只会删去字段和字段排列顺序都完全匹配的文档元素
      1. 相当于{ $pull : { <field1 > : { $in :[ <value1>,<value2> ] } } }
      2. 如果要删去的元素是一个数组,数组元素的值和排列顺序都必须和被删除的数组完全一样
        1. db.accounts.update({name:"lawrence"},{$pull:{contact:{$in:[2222,3333]}}})
        2. db.accounts.update({name:"lawrence"},{$pullAll:{contact:[[2222,3333]]}})
 
    1. {$push:{<field1>:<value1>,...}}
      1. db.accounts.update({name:"lawrence"},{$push:{newArray:"new element"}})
      2. db.accounts.update({name:"lawrence"},{$push:{newArray:{$each:[2,3,4]}}});
      3. db.accounts.update({name:"lawrence"},{$push:{newArray:{$each:["pos1","pos2"],$position:0}}} );
        1. 使用position 指定新插入字段的位置。
      4. db.accounts.update({name:"lawrence"},{$push:{newArray:{$each:[11],$sort:1}}})
        1. 插如新元素对数组进行排序,1为正序,-1为倒序
      5. db.accounts.update({name:"lawrence"},{$push:{newArray:{$each:[{key:"sort",value:100}],$sort:{value:-1}}}})
        1. 数组插入内嵌文档,指定排序为 内嵌文档value的值
      6. db.accounts.update({name:"lawrence"},{$push:{newArray:{$each:[3],$slice:-3}}})
        1. 数组插入 并截取按指定长度截取
      7. 这三个操作符的执行顺序 : $position $sort $slice写在命令中的操作符顺序并不会影响到执行顺序
        1. 一定要注意
      8. db.collection.update({<array>:<query selector>},{<update operator>:{"<array>.$":value}})
        1. 更新数组中的特定元素 $是数组中第一个符合筛选条件的数组元素的占位符
        2. db.accounts.update({name:'lawrence',newArray:"push1"},{$set:{'newArray.$':"updated"}})
          1. 把push1 更新成了 updated
      9. db.accounts.update({name:"bill"},{$set:{ "newArray.$[]":'value'}})
        1. 数组全部更新成value
 
  1. db.<collection>.update(<query>,<update>,<options>) 更新文档选项
 
    1. { multi:<boolean> } 更新多个文档
      1. db.accounts.update({name:"lawrence"},{$set:{currency:"USD"}},{multi:true})
      2. 注意 MongoDB 只能保证*单个*文档操作的原子性,不能保证*多个*文档操作的原子性(中间有可能被打断,可能被其他线程更新)。更新多个文档的操作虽然在单一线程中执行,但是线程在执行过程中可能被挂起,以便其他线程也有机会对数据进行操作。
      3. 如果需要保证多个文档操作时的原子性,就需要使用MongoDB4.0版本引入的事务功能进行操作。
 
    1. { upsert : <boolean> } 更新或创建文档 upsert设置为true,如果update命令中的筛选条件没有匹配文档,则会新建新文档(筛选条件也会新建)
      1. db.accounts.update({name:"meggie"},{$set:{balance:800}},{upsert:true})
      2. db.accounts.update({balance:{$gt:20000}},{$set:{name:"nick"}},{upsert:true})
        1. 如果无法从筛选条件中推断出确定的字段值,新创建的文档将不会包含筛选条件涉及的字段,但仍然会创建新文档 。{ "_id" : ObjectId("5dd6b160ebece8a7ca7cab20"), "name" : "nick" }
 
  1. db.<collection>.save(<document>)
    1. 如果document文档中包含了_id字段,save()命令将会调用db.collection.update()命令(upsert:true)
    2. db.accounts.save({_id:"account1",name:"davidd",balance:100})
 
 
MongoDB 之 DELETE
  • db.collection.remove() 删除文档 但是不会删除集合
    • db.accounts.remove({balance:200}) 会删除所有满足条件的文档
 
  • db.accounts.remove({balance:{$lt:200}},{justOne:true})
    • 如果只想删除满足筛选条件的*第一篇*文档,可以使用justOne选项
 
  • db.accounts.remove( {} ) 删除所有文档,但是并不会删除集合
 
  • db.collection.drop() 删除集合
    • db.<collection>.drop( { writeConcern : <document> } )
    • writeConcern文档定义了本次集合删除操作的安全写级别
  • 如果集合中文档数量很多,使用remove命令删除所有文档的效率不高,这种情况下,更加有效率的方法。是使用drop命令删除集合,再创建新集合。

posted @ 2021-03-03 13:58  year12  阅读(57)  评论(0编辑  收藏  举报