Mongodb文档的CURD操作
Minbin Jiang Lv4

从当年写毕业论文学习如何使用mongodb,到现在陆陆续续的在使用。一直都没有系统的去看看mongodb的文档。由于moogoose的原因,最近又在操作
mongodb,想想磨刀不误砍柴工,看看文档,动动笔记录记录。

在mongodb中有db,collection,document数据模型,今天先来说说mongodb的基元document的操作。mongodb所有的操作都围绕document来做。document相当于
传统关系型数据库中的row

插入document

类似关系型数据库,一条条的row插入到table中,而NoSql中的一个个document 插入到collection中。

插入document的语句有如下几种:

  1. db.collection_name.insert()
  2. db.collection_name.insertOne()
  3. db.collection_name.insertMany()

通过字面意思也知道这几种插入方法的不同。其中1既可以插入一个document,也可以插入多个。而2,3是后续版本中添加的。mongodb的所有的写操作都是原子(atomic)

mongodb的document都包含一个 _id 字段,该字段类似于关系型数据库中的primary
key
。其中_id可以在插入文档候自定义赋值,如

db.some_col.insert({"_id":6,
    "name": 'suwen'
    })

也可以不显示指明,如果没有显示指明则mongodb会根据时间戳+pid+随机数信息生成一个类型为objectid的_id 值。如:

db.some_col.insert({"name":'suwen'})

通过查询,其_id值为5750f3b164cfe92c28a4c2b1。且mongodb含有从 _id中提取时时间戳信息的命令。

查询document

在mongo中document的查询语句如下:

  1. db.collection.find(<query>,<projection>)
  2. db.collection.findOne(<query>,<projection>)

其中query为查询语句,而为optional参数对查询返回的字段进行过滤。可以控制查询结果的传输量。

其中findOne可以直接获取一个document,而find获取多个document。则在获取document的中的某个字段值的时候需要注意。如:

var dd=db.testpoint.findOne({name:"id1"})
dd.name // id1

var dd=db.testpoint.find({name:"id1"})

dd.name //no result to show
dd[0].name //id1

当find()不添加任何参数或者参数为{}的时候,表示查询当前collection中的所有document。

  • project

project格式如下:{field1:,field2:..}其中字段值只有0和1两类。其中0表示字段排除,1表示字段包含。

db.testpoint.findOne({name:"id1"},{_id:0}) //查询结果不包含_id 信息
  • query

mongo提供了非常丰富的query,来应用不同场景的查询。

大体分为下面几类:

1.简单相等查询

db.some_col.find({"name":"suwen"})

AND条件查询,直接多个字段

db.some_col.find({"name":"suwen",'gender':'male'})

其他的OR条件或者比较查询需要与操作符进搭配使用。

2.与操作符结合判断

mongod提供了一些犹如关系型数据库中的操作符$in,$lt等。如

db.some_col.find({"name":{$in:["suwen,mb"]}})

用法和关系型数据库的in操作符一样。后面会专门写篇文章来学习这些关键字。

3.嵌套和引用文档的查询
mongodb 通过嵌套和应用构建复杂的document,这两者怎么查询呢?

有如下document:


db.users.insert([{
    username: 'suwen',
    contact: { //嵌套document
        phone: '111111111',
        email: '1111@qq.com'},
    department: { //嵌套document
        level: 0,
        title: "giser"},
    
    hobby: ['eating','sleeping','hit doudou'] //Array
},
{
    username: 'jmb',
    contact: { //嵌套document
        phone: '222222222',
        email: '2222@qq.com'},
    department: { //嵌套document
        level: 0,
        title: "loser"
    },
    hobby: ['sleeping','eating'] //Array
}])

嵌套document的查询有两种方式:

一是文档完全匹配的形式

如find上面的记录需要使用如下语句:

db.users.find(
{
 contact: { 
        phone: '111111111',
        email: '1111@qq.com'
    }
})

那么如果我只想以电话作为条件是不是可以使用如下这种形式????

db.users.find(
{
 contact: { 
        phone: '111111111'
       
    }
}) //no results

执行完,发现并没有结果出现。。这也是为何这种方式叫文档完全匹配。如果只使用嵌套文档中的某个字段作为条件来过滤,则需要使用如下第二种方式:

二是通过dot notation的形式,该形式的格式为<document>.<field>

db.users.find(
{
 'contact.phone':'111111111'
})

4.Array的查询

有了上面几个基础,再来理解Array的查询就容易多了。 document的字段值可能是一个Array类型。如何对Array的值进行判断,从而来筛选document呢?

一是完全匹配形式。

db.users.find({ hobby: ['eating','sleeping','hit doudou']})

同样其为整个Array的匹配。只有全部匹配的Array才能筛选出。

二是匹配Array中的某个元素
针对Array中的某个元素的匹配,可以使用犹如普通的筛选语句。

db.users.find({ hobby: 'hit doudou'})

除此之外,array还有一种常见方式
三对Array某个位置的元素进行匹配
如对array的index的value为’eating’的进行匹配。

db.users.find({ "hobby.0": 'eating'})

Array除此上面三种方式,还有更为复杂条件匹配。此处按下不表。

update

这个就厉害了。

  1. db.collection.update()
  2. db.collection.updateOne()
  3. db.collection.updateMany()
  4. db.collection.replaceOne()

其中upate(<query>,<update>,<upsert>,<multi>,<writeConcern>)方法用来更新或者替代匹配的文档。其中前两个参数为必填参数。

query为匹配的条件filter,update为更新的内容,upsert这个参数厉害了,当通过query查找没有匹配的document的且upsert参数为true,这个时候,将会在collection中去insert一条document。而multi指定是否同时更新多个document。

前面说到update()用来更新或者替换,那么问题来了,什么时候是对document的更新,什么是替换整个document。

当upate的document中有update操作符如$set,$unset才为更新操作,否则用该document替换匹配的document

细思极恐啊。万一这要是弄混淆了。。。不知道mongodb怎么会这么设计。我想这也是为何在后续版本中,将update()方法拆分几个方法的原因。

delete操作

删除操作有如下几个语句

  1. db.collection.remove()
  2. db.collection.deleteOne()
  3. db.collection.deleteMany()

用法类似,语法如:revmove(<query>,<justone>,<writeConcern>)。其中query为匹配的条件,其和查询中的条件格式一
样。默认情况下,remove对所有匹配的记录进行删除,但是通过将参数justone设置为true,则只删除匹配记录中的一条记录。那么问题来了,如果匹配多
个记录该删除那条呢?此时官方文档狡猾的推荐使用db.collection.findAndDelete()。可以对查询的结果按照条件排序,然后再删除第一条记录。

##总结
mongodb在版本迭代的过程中,一个操作有多个方式实现。个人觉着还是使用更为精细的控制,比如插入用insertOne或者insertMany。避免造成不必要的误操作。

更多参考

MongoDB CRUD Operations