mongo使用总结

总结在8月份开发过程中对mongo使用经验

mongo的基本操作

数组中元素的修改都是基于这按元素查询$elemMatch而来,然后通过$来选择哪一个

数组的元素查询

  • 实例
  this.db.collection("tunnelWorkSection").findOne(
   {
        tunnelID:tunnelID,
        workSectionList:{$elemMatch:{workSectionName: workSection}}
   },
   {
        _id:0, "workSectionList.$":1
   }
 )

这样的结果竟然只查询了一个结果,即若workSectionName有多个匹配结果会只查出一个,即使使用find也是如此。

  • 倒不如用unwind方法来进行查询
  db.tunnelWorkSection.aggregate([{$match:{tunnelID:tunnelID}},{$unwind:"$workSectionList"}, {$match:{"workSectionList.workSectionName": workSection}}])

如此查询的结果就是查询到了所有的,但是拍平的结果。

数组中元素的修改

  • 实例
  await this.db.collection("tunnelWorkSection").updateOne(
    {
       tunnelID: tunnelID, 
       workSectionList:{$elemMatch:{workSectionName: workSection}}
    },
    {$inc: {'workSectionList.$.finishLength': finishLength } }
  )

数组中元素的删除

按之前的写法,应该很容易写成下边方法

 await this.db.collection("tunnelWorkSection").updateOne(
    {
       tunnelID: tunnelID, 
       workSectionList:{$elemMatch:{workSectionName: workSection}}
    },
    {$pull: {workSectionList:'workSectionList.$'} }
  )

但很不幸的是,不好使。原因大概是'workSectionList.$'放在value上,只会被认为是字符串。经过几次测试,从数组中删除元素只需要如此即可,pull与pullAll:

db.students.update({tunnelID:tunnelID},{$pull:{workSectionList:{workSectionName:workSection}}})

        await this.db.collection(this.tunnelFixtureCollection).updateOne(
            {tunnelId:tunnelId, fixtureType:fixtureType},
            {$pull:
                {
                    designValueList:{layer:layer, subCode:subCode}
                } 
            }

思考

完成了对mongo数组中操作的整理后,发现这方面的资料很少
于是有些怀疑在数组中放置对每个元素进行操作的这种设计:查询时最终的方案是通过unwind之后进行的查询,unwind造成的结果是本来数组中的元素被扁平到外部,这也暗示这如果用户对数组中的元素感兴趣,它完全可以能就忽视了外层的信息,也就说明,这数组中的元素应该放到单独的表中。

mongo表的设计

设计总结

  • 内嵌 or 链接
    内嵌文档可以将整个数据组织在一个集合中,隧道内嵌工作段,工作段内嵌进尺,进尺内嵌消耗量。但这种内嵌,一方面是内嵌层数变身以后带来的效率的下降,最重要的是操作实现上的难度。

    字典内嵌
    字典应该不属于内嵌,因为它的key值相当于属性,只能通过update的unset与set进行删除与新增。访问上可以通过 "." 来实现快速的查询。
    1对多关系中的数据不应该放在字典内嵌中,字典内嵌说明着这些数据地位是不同的,但多中每个1的地位是相同的。
    如果内嵌能实现的化,字典内嵌应该是最有希望的。

    数组内嵌
    数组类型就是来存储这种1对多关系的,将多方作为元素放在1方的某个属性的value数组里。
    这种使用方式就是如mongo基本操作中的内容,如果这些数组作为整体来查询,或者删除比较适合,对于个体进行

链接
链接就像是关系型数据库类似,通过增加一个字段来完成链接,或者是增加一个保存ID的数组来完成。
链接也存在问题,因为mongo本身不提供join以及事务,多表操作会存在一定的风险。

特性

  • mongo每条记录都是一个文档,都是Json扩展的Bson
    所以mongo中每个集合中的文档,可以完全不同。
    从使用上,我们将文档当作成表的行来使用。

  • mongo的多个记录组成了集合
    使用上集合当作表来使用

  • mongo不支持事务

  • mongo没有多表的join查询

设计原则

一对很少

采用内嵌文档
person集合中

  {
     name:'张三',
     age:20,
     address:[
      {country:"中国",province:"山西省",city:"长治市"},
      {country:"中国",province:"山西省",city:"太原市"}
     ]
   
   }

优点:不需要单独执行一条语句去获取内嵌的内容
缺点:法把这些内嵌文档当做单独的实体去访问
适用场合:一对很少且不需要单独访问内嵌内容

一对少

person集合
{
  _id:ObjectID(12个字节组成)
  name:"张三"
  age:23
}

人员组集合
{
  name:"一组",
  persons:[
    ObjectID("aaaaa"),
    ObjectID("AAABBB")]
}  

适用场合:一对多且多的一端内容因为各种理由需要单独存在的情况下可以通过数组的方式引用多的一方的。

一对多

company集合
{
  _id:ObjectID("company01")
  name:"可为时代"
}

员工集合
{
  name:"张三",
  age:23,
  company:ObjectID("company01")
}

适用场合:一对非常多的情况下,请将一的那端引用嵌入进多的一端对象中。

多对多

双向的连接,一对多,多对1

原则

a.优先考虑内嵌,除非有什么迫不得已的原因。

b.需要单独访问一个对象,那这个对象就不适合被内嵌到其他对象中。

c.数组不应该无限制增长。如果many端有数百个文档对象就不要去内嵌他们可以采用引用ObjectID的方案;如果有数千个文档对象,那么就不要内嵌ObjectID的数组。该采取哪些方案取决于数组的大小。

d.在进行反范式设计时请先确认读写比。一个几乎不更改只是读取的字段才适合冗余到其他对象中。

问题

  • 分组TOP N
  • 解析器 或 状态机
  • 多条件查询

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×