• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

mongodb-13.查询,原子操作,高级索引

武飞扬头像
yan_baby_liu
帮助1

查询分析

$explain

$hint 运算符(也叫“强制查询优化器”)能够使用指定的索引来进行查询,以此来测试查询的性能。当您想要测试具有不同索引的查询性能时,此功能特别有用

原子操作

在MongoDB Compass中,用Mongosh中输入原生执行命令,回车用shift enter

>db.productDetails.insertOne({
  product_name:'Sansung S3',
  category:'mobiles',
  product_total:5,
  procuct_available:3,
  product_bought_by:[
    {
      customer:'john',
      date:'7-Jan-2014'
    },
    {
      customer:'mark',
      date:'8-Jan-2014'
    }
    ]
  
})
{ acknowledged: true,
  insertedId: ObjectId("63abf8322574a3d57b1902aa") }


db.productDetails.find()
{ _id: ObjectId("63abf8322574a3d57b1902aa"),
  product_name: 'Sansung S3',
  category: 'mobiles',
  product_total: 5,
  procuct_available: 3,
  product_bought_by: 
   [ { customer: 'john', date: '7-Jan-2014' },
     { customer: 'mark', date: '8-Jan-2014' } ] }
学新通

原子操作findAndModify

db.productDetails.findAndModify({
  query:{
    _id:ObjectId("63abf8322574a3d57b1902aa"),
    procuct_available:{$gt:0}
  },
  update:{
    $inc:{
      procuct_available:-1
    },
    $push:{
      product_bought_by:{
        customer:'yanwl',
        date:'16-Dec-2022'
      }
    }
  }
})
学新通

常用的原子操作命令

$set
用来指定一个键并更新键值,若键不存在则创建。

{ $set : { field : value } }

$unset
用来删除一个键。

{ $unset : { field : 1} }

$inc
用来对文档的某个数值类型的键值进行增减操作。

{ $inc : { field : value } }

$push
用来向文档中追加一些信息。

{ $push : { field : value } }

把 value 追加到 field 里面去,field 一定要是数组类型才行,如果 field 不存在,则会新增一个数组类型加进去。
$pushAll
与 $push 类似,它可以一次追加多个值到一个数组类型的字段内。

{ $pushAll : { field : value_array } }

$pull
从数组 field 内删除一个等于 value 的值。

{ $pull : { field : _value } }

$pop
删除数组的第一个或最后一个元素。

{ $pop : { field : 1 } }

$rename
修改字段的名称。

{ $rename : { old_field_name : new_field_name } }

$bit
位操作,integer 类型。

{$bit : { field : {and : 5}}}

偏移操作符

t.find() { “_id” : ObjectId(“4b97e62bf1d8c7152c9ccb74”), “title” : “ABC”, “comments” : [ { “by” : “joe”, “votes” : 3 }, { “by” : “jane”, “votes” : 7 } ] }
t.update( {‘comments.by’:‘joe’}, {KaTeX parse error: Expected '}', got 'EOF' at end of input: inc:{'comments..votes’:1}}, false, true )
t.find() { “_id” : ObjectId(“4b97e62bf1d8c7152c9ccb74”), “title” : “ABC”, “comments” : [ { “by” : “joe”, “votes” : 4 }, { “by” : “jane”, “votes” : 7 } ] }

高级索引

索引数组字段

db.users.insert(
 {
 "address": {
 "city": "Hebei",
 "country": "China",
 "postcode": "000000"
 },
 "tags": [
 "music",
 "cricket",
 "blogs"
 ],
 "name": "bianchengbang"
 }
)
{ acknowledged: true,
  insertedIds: { '0': ObjectId("63ac02032574a3d57b1902ab") } }
学新通

在上面的文档中包含了一个名为 address 的子文档和一个名为 tags 的数组。 索引数组字段
假设要想根据集合内 tags 字段中的某个值来搜索用户文档,就需要我们为集合中的 tags 字段创建索引。想要在数组类型的字段上创建索引,需要为数组中的每个字段依次创建单独的索引。

在下面的示例中,当我们在 tags 字段上创建索引时,MongoDB 会自动在 music、cricket 和 blogs 等值上创建单独的索引。

>db.users.createIndex({
  tags:1
})
>'tags_1'
>db.users.getIndexes()
[
  { v: 2, key: { _id: 1 }, name: '_id_' },
  { v: 2, key: { tags: 1 }, name: 'tags_1' }
]
>db.users.find({tags:'cricket'}).pretty()
<{ _id: ObjectId("63ac02032574a3d57b1902ab"),
  address: { city: 'Hebei', country: 'China', postcode: '000000' },
  tags: [ 'music', 'cricket', 'blogs' ],
  name: 'bianchengbang' }
>db.users.find({tags:'cricket'}).explain()
<{ queryPlanner: 
   { plannerVersion: 1,
     namespace: 'test.users',
     indexFilterSet: false,
     parsedQuery: { tags: { '$eq': 'cricket' } },
     winningPlan: 
      { stage: 'FETCH',
        inputStage: 
         { stage: 'IXSCAN',
           keyPattern: { tags: 1 },
           indexName: 'tags_1',
           isMultiKey: true,
           multiKeyPaths: { tags: [ 'tags' ] },
           isUnique: false,
           isSparse: false,
           isPartial: false,
           indexVersion: 2,
           direction: 'forward',
           indexBounds: { tags: [ '["cricket", "cricket"]' ] } } },
     rejectedPlans: [] },
  serverInfo: 
   { host: 'node4',
     port: 27017,
     version: '4.4.17',
     gitVersion: '85de0cc83f4dc64dbbac7fe028a4866228c1b5d1' },
  ok: 1,
  '$clusterTime': 
   { clusterTime: Timestamp({ t: 1672217366, i: 1 }),
     signature: 
      { hash: Binary(Buffer.from("0000000000000000000000000000000000000000", "hex"), 0),
        keyId: 0 } },
  operationTime: Timestamp({ t: 1672217366, i: 1 }) }
学新通

索引子文档字段

创建子文档索引以前

>db.users.find({'address.city':'Hebei'})
<{ _id: ObjectId("63ac02032574a3d57b1902ab"),
  address: { city: 'Hebei', country: 'China', postcode: '000000' },
  tags: [ 'music', 'cricket', 'blogs' ],
  name: 'bianchengbang' }
>db.users.find({'address.city':'Hebei'}).explain()
<{ queryPlanner: 
   { plannerVersion: 1,
     namespace: 'test.users',
     indexFilterSet: false,
     parsedQuery: { 'address.city': { '$eq': 'Hebei' } },
     winningPlan: 
      { stage: 'COLLSCAN',
        filter: { 'address.city': { '$eq': 'Hebei' } },
        direction: 'forward' },
     rejectedPlans: [] },
  serverInfo: 
   { host: 'node4',
     port: 27017,
     version: '4.4.17',
     gitVersion: '85de0cc83f4dc64dbbac7fe028a4866228c1b5d1' },
  ok: 1,
  '$clusterTime': 
   { clusterTime: Timestamp({ t: 1672217756, i: 1 }),
     signature: 
      { hash: Binary(Buffer.from("0000000000000000000000000000000000000000", "hex"), 0),
        keyId: 0 } },
  operationTime: Timestamp({ t: 1672217756, i: 1 }) }
学新通

创建索引

>db.users.ensureIndex({'address.city':1,'address.country':1,'address.postcode':1})
<[ 'address.city_1_address.country_1_address.postcode_1' ]

>db.users.find({'address.city':'Hebei'}).explain()
<{ queryPlanner: 
   { plannerVersion: 1,
     namespace: 'test.users',
     indexFilterSet: false,
     parsedQuery: { 'address.city': { '$eq': 'Hebei' } },
     winningPlan: 
      { stage: 'FETCH',
        inputStage: 
         { stage: 'IXSCAN',
           keyPattern: 
            { 'address.city': 1,
              'address.country': 1,
              'address.postcode': 1 },
           indexName: 'address.city_1_address.country_1_address.postcode_1',
           isMultiKey: false,
           multiKeyPaths: 
            { 'address.city': [],
              'address.country': [],
              'address.postcode': [] },
           isUnique: false,
           isSparse: false,
           isPartial: false,
           indexVersion: 2,
           direction: 'forward',
           indexBounds: 
            { 'address.city': [ '["Hebei", "Hebei"]' ],
              'address.country': [ '[MinKey, MaxKey]' ],
              'address.postcode': [ '[MinKey, MaxKey]' ] } } },
     rejectedPlans: [] },
  serverInfo: 
   { host: 'node4',
     port: 27017,
     version: '4.4.17',
     gitVersion: '85de0cc83f4dc64dbbac7fe028a4866228c1b5d1' },
  ok: 1,
  '$clusterTime': 
   { clusterTime: Timestamp({ t: 1672217966, i: 1 }),
     signature: 
      { hash: Binary(Buffer.from("0000000000000000000000000000000000000000", "hex"), 0),
        keyId: 0 } },
  operationTime: Timestamp({ t: 1672217966, i: 1 }) }
学新通

索引注意事项

额外开销
每个索引都会占用一些空间,并且在每次执行插入、更新和删除等操作时也需要对索引进行操作,导致额外的开销。因此,如果您很少将某个集合用于读取操作,最好不要在集合中使用索引。
RAM 使用
由于索引存储在 RAM(内存)中,因此应确保索引的总大小不超过 RAM 的限制。如果总大小大于 RAM 的大小,那么 MongoDB 将删除一些索引,这就会导致性能下降。
查询限制
在以下的查询中,不能使用索引:
正则表达式或否定运算符,例如 n i n 、 nin、 ninnot 等;
算术运算符,例如 $mod 等;
$where 子句。

因此,建议经常使用 explain() 来检查查询时索引的使用情况。
索引键限制
从 2.6 版本开始,如果现有索引字段的值超过索引键的限制,那么 MongoDB 将不会创建索引。
插入超过索引键限制的文档
如果文档索引字段的值超过了索引键的限制,那么 MongoDB 不会将任何文档插入到集合中。mongorestore 和 mongoimport 实用程序也是如此。
最大范围
在定义索引时有以下几点需要注意:
集合的索引不能超过 64 个;
索引名称的长度不能超过 128 个字符;
复合索引最多可以拥有 31 个字段。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgkfiba
系列文章
更多 icon
同类精品
更多 icon
继续加载