ql

予早 2026-04-30 23:53:28
Categories: Tags:

聚合

 db.getCollection("author2books").insertMany([
     {
         "_id": ObjectId("5e05fe4a32780f42806a80c5"),
         "author": "tom",
         "books": [
             {"type": "IT类", "name": "mongodb", "price": NumberInt("100")},
             {"type": "IT类", "name": "java", "price": NumberInt("50")},
             {"type": "文学类", "name": "红楼梦", "price": NumberInt("20")}
         ],
         "year": NumberInt("2018")
     },
     {
         "_id": ObjectId("5e05fe6032780f42806a80c7"),
         "author": "tom",
         "books": [{"type": "IT类", "name": "程序员的修养", "price": NumberInt("30")},
                   {"type": "文学类", "name": "简爱", "price": NumberInt("50")},
                   {"type": "哲学类", "name": "西方哲学史", "price": NumberInt("20")}
                   ],
         "year": "2019"
     },
     {
         "_id": ObjectId("5e05fe6332780f42806a80c9"),
         "author": "jack",
         "books": [{"type": "IT类", "name": "程序员的修养", "price": NumberInt("30")},
                   {"type": "文学类", "name": "简爱", "price": NumberInt("50")},
                   {"type": "哲学类", "name": "西方哲学史", "price": NumberInt("20")}
                   ],
         "year": "2019"
     },
     {
         "_id": ObjectId("5e0854c432780f0d80c7bb43"),
         "author": "jack",
         "books": [{"type": "IT类", "name": "程序员的修养", "price": NumberInt("30")},
                   {"type": "IT类", "name": "高并发编程", "price": NumberInt("50")}
                   ],
         "year": "2018"
     }
 ])
 

查询2018年每个人在每种书的类别下写了多少本书?

 db.author2books.aggregate([
   {$match: {year:2018}},
     {$unwind:  "$books" },// 数组flat展开
     {$group:{"_id":{"author": "$author",  "bookType":"$books.type"},count:{$sum:1}  }},
     {$project:{ "_id":0, "author":"$_id.author" , "bookType":"$_id.bookType", "bookTypeCnt":"$count"}}, // 美化分组结果,可以单独看看分组结果对比一下
     {$sort:{author:-1}}
 ]);

插入

批量写操作

 db.collection.bulkWrite(
    [ <operation 1>, <operation 2>, ... ],
    {
       writeConcern : <document>,
       ordered : <boolean>
    }
 )
 

参数 类型 描述 operations array bulkWrite() 写操作的数组。支持操作:insertOne、updateOne、updateMany、deleteOne、deleteMany、replaceOne writeConcern document 可选, write concern 文档,省略则使用默认的 write concern。 ordered boolean 可选,表示mongod实例有序还是无序执行操作。默认值true。

方法返回值:

insertOne

插入单个文档到集合中。

 db.collection.bulkWrite( [
    { insertOne : { "document" : <document> } }
 ] )
 

updateOne 及 updateMany updateOne 更新集合中 filter 匹配的单个文档。如果匹配到多个文档 updateOne 仅更新第一个匹配到的文档。

 db.collection.bulkWrite( [
    { updateOne :
       {
          "filter" : <document>,
          "update" : <document>,
          "upsert" : <boolean>
       }
    }
 ] )
 

updateMany 更新集合中所有匹配到的文档。

 db.collection.bulkWrite( [
    { updateMany :
       {
          "filter" : <document>,
          "update" : <document>,
          "upsert" : <boolean>
       }
    }
 ] )
 

replaceOne

replaceOne 替换集合中 filter 匹配到的单个文档。如果匹配到多个文档 replaceOne 只会替换一个匹配到的文档。

 db.collection.bulkWrite([
    { replaceOne :
       {
          "filter" : <document>,
          "replacement" : <document>,
          "upsert" : <boolean>
       }
    }
 ] )
 

replacement 字段中不能包含 update 操作。

deleteOne 及 deleteMany

deleteOne 删除集合中 filter 匹配到的单个文档。如果匹配到多个文档 deleteOne 只会删除一个匹配到的文档。

 db.collection.bulkWrite([
    { deleteOne :  { "filter" : <document> } }
 ] )
 
 db.collection.bulkWrite([
    { deleteMany :  { "filter" : <document> } }
 ] )
 

默认情况下 ordered : true ,每个操作将会有序的执行,从第一个insertOne 到最后一个deleteMany 顺序执行。

应用程序不依赖操作执行顺序是,可以设置 ordered 为 false ,此时mongod 会重新排序操作来提高性能。

对于ordered:false,操作结果可能会有所不同。 例如,deleteOne或deleteMany 删除的文档可能会变多或变少,具体取决于deleteOne或deleteMany 是在insertOne,updateOne,updateMany或replaceOne操作之前或之后的运行。

每组操作最多可以有1000次操作。 如果一个组超过此限制,MongoDB会将该组划分为1000或更小的组。 例如,如果队列包含2000个操作,MongoDB将创建2个组,每个组具有1000个操作。

大小和分组机制是内部的执行细节,在将来的版本中可能会有所变化。

在分片集合上执行有序操作通常比执行无序操作慢,因为对于有序,每个操作必须等待上一个操作完成。

bulkWrite() 在错误发生时会抛出 BulkWriteError 异常。

排除Write Concern错误,有序操作在发生错误后停止,及无序操作继续处理队列中的剩余写入操作。

Write Concern 错误显示在 writeConcernErrors字段中,而所有其他错误都显示在writeErrors字段中。 如果遇到错误,则显示成功写入操作的数量而不是插入的

示例

characters 集合包含以下文档:

 { "_id" : 1, "char" : "Brisbane", "class" : "monk", "lvl" : 4 },
 { "_id" : 2, "char" : "Eldon", "class" : "alchemist", "lvl" : 3 },
 { "_id" : 3, "char" : "Meldane", "class" : "ranger", "lvl" : 3 }

有序批量写

 try {
    db.characters.bulkWrite(
       [
          { insertOne :
             {
                "document" :
                {
                   "_id" : 4, "char" : "Dithras", "class" : "barbarian", "lvl" : 4
                }
             }
          },
          { insertOne :
             {
                "document" :
                {
                   "_id" : 5, "char" : "Taeln", "class" : "fighter", "lvl" : 3
                }
             }
          },
          { updateOne :
             {
                "filter" : { "char" : "Eldon" },
                "update" : { $set : { "status" : "Critical Injury" } }
             }
          },
          { deleteOne :
             { "filter" : { "char" : "Brisbane"} }
          },
          { replaceOne :
             {
                "filter" : { "char" : "Meldane" },
                "replacement" : { "char" : "Tanys", "class" : "oracle", "lvl" : 4 }
             }
          }
       ]
    );
 }
 catch (e) {
    print(e);
 }
 
 {
    "acknowledged" : true,
    "deletedCount" : 1,
    "insertedCount" : 2,
    "matchedCount" : 2,
    "upsertedCount" : 0,
    "insertedIds" : {
       "0" : 4,
       "1" : 5
    },
    "upsertedIds" : {
  
    }
 }
 

如果 第二个 insertOne 操作的 _id 是集合中已经存在的,则会抛出以下错误,默认情况下 ordered 为 true, 顺序执行时遇到错误就停止执行(后续的操作不会被执行)。:

 BulkWriteError({
    "writeErrors" : [
       {
          "index" : 0,
          "code" : 11000,
          "errmsg" : "E11000 duplicate key error collection: guidebook.characters index: _id_ dup key: { : 4 }",
          "op" : {
             "_id" : 5,
             "char" : "Taeln"
          }
       }
    ],
    "writeConcernErrors" : [ ],
    "nInserted" : 1,
    "nUpserted" : 0,
    "nMatched" : 0,
    "nModified" : 0,
    "nRemoved" : 0,
    "upserted" : [ ]
 })
 

无序批量写

 { "_id" : 1, "char" : "Brisbane", "class" : "monk", "lvl" : 4 },
 { "_id" : 2, "char" : "Eldon", "class" : "alchemist", "lvl" : 3 },
 { "_id" : 3, "char" : "Meldane", "class" : "ranger", "lvl" : 3 }
 try {
    db.characters.bulkWrite(
          [
             { insertOne :
                {
                   "document" :
                   {
                      "_id" : 4, "char" : "Dithras", "class" : "barbarian", "lvl" : 4
                   }
                }
             },
             { insertOne :
                {
                   "document" :
                      {
                         "_id" : 4, "char" : "Taeln", "class" : "fighter", "lvl" : 3
                      }
                }
             },
             { updateOne :
                {
                   "filter" : { "char" : "Eldon" },
                   "update" : { $set : { "status" : "Critical Injury" } }
                }
             },
             { deleteOne :
                { "filter" : { "char" : "Brisbane"} }
             },
             { replaceOne :
                {
                   "filter" : { "char" : "Meldane" },
                   "replacement" : { "char" : "Tanys", "class" : "oracle", "lvl" : 4 }
                }
             }
          ],
             { ordered : false }
       );
    }
    catch (e) {
    print(e);
 }
 
 BulkWriteError({
    "writeErrors" : [
       {
          "index" : 0,
          "code" : 11000,
          "errmsg" : "E11000 duplicate key error collection: guidebook.characters index: _id_ dup key: { : 4 }",
          "op" : {
             "_id" : 4,
             "char" : "Taeln"
          }
       }
    ],
    "writeConcernErrors" : [ ],
    "nInserted" : 1,
    "nUpserted" : 0,
    "nMatched" : 2,
    "nModified" : 2,
    "nRemoved" : 1,
    "upserted" : [ ]
 })
 

无序操作,尽管操作过程中出现错误,剩余的操作也不会就此终止执行。

write concern

enemies 集合包含以下文档:

 { "_id" : 1, "char" : "goblin", "rating" : 1, "encounter" : 0.24 },
 { "_id" : 2, "char" : "hobgoblin", "rating" : 1.5, "encounter" : 0.30 },
 { "_id" : 3, "char" : "ogre", "rating" : 3, "encounter" : 0.2 },
 { "_id" : 4, "char" : "ogre berserker" , "rating" : 3.5, "encounter" : 0.12}

以下使用 write concern 值为 “majority” 及 timeout 为 100 毫秒来执行批量写操作:

 try {
    db.enemies.bulkWrite(
       [
          { updateMany :
             {
                "filter" : { "rating" : { $gte : 3} },
                "update" : { $inc : { "encounter" : 0.1 } }
             },
  
          },
          { updateMany :
             {
                "filter" : { "rating" : { $lt : 2} },
                "update" : { $inc : { "encounter" : -0.25 } }
             },
          },
          { deleteMany : { "filter" : { "encounter" { $lt : 0 } } } },
          { insertOne :
             {
                "document" :
                   {
                      "_id" :5, "char" : "ogrekin" , "rating" : 2, "encounter" : 0.31
                   }
             }
          }
       ],
       { writeConcern : { w : "majority", wtimeout : 100 } }
    );
 }
 catch (e) {
    print(e);
 }
 

如果副本集中所有必需节点确认写入操作所需的总时间大于wtimeout,则在wtimeout 时间过去时将显示以下writeConcernError。

 BulkWriteError({
    "writeErrors" : [ ],
    "writeConcernErrors" : [
       {
          "code" : 64,
          "errInfo" : {
             "wtimeout" : true
          },
          "errmsg" : "waiting for replication timed out"
       }
    ],
    "nInserted" : 1,
    "nUpserted" : 0,
    "nMatched" : 4,
    "nModified" : 4,
    "nRemoved" : 1,
    "upserted" : [ ]
    })
 

结果集显示执行的操作,因为writeConcernErrors错误不是任何写入操作失败的标志。

pymongo需要objectid才行,不会自动转

获取指定字段和去重不能在一般语句同时使用,要使用聚合

 db.getCollection("pri_product_initial").find({}).count()  // 1293319
 db.getCollection("pri_product_initial").find({"bonus_type": "0"}).count() // 50060
 db.getCollection("pri_product_initial").find({"bonus_type": "1"}).count() // 103
 db.getCollection("pri_product_initial").find({"bonus_type": {"$exists": false}}).count() // 103
 db.pri_product_initial.aggregate([
     {
       "$match": {
                 "bonus_type": {"$exists": true}
       }
     }, {
       "$project": {
           "bonus_type": 1
       }
     }, {"$group": {"_id": "$bonus_type", "count": {"$sum": 1}}},
   ]
 )
 
 db.getCollection("pri_product_initial").distinct("bonus_type").find({}, {"bonus_type": 1})  // 1293319
 
 db.getCollection("pri_product").find({}).count()  // 362185
 db.getCollection("pri_product").find({"bonus_type": "0"}).count() // 277157
 db.getCollection("pri_product").find({"bonus_type": "1"}).count() // 353
 db.getCollection("pri_product").find({"bonus_type": {"$exists": false}}).count() // 103
 db.pri_product.aggregate([
     {
       "$match": {
                 "bonus_type": {"$exists": true}
       }
     }, {
       "$project": {
           "bonus_type": 1
       }
     }, {"$group": {"_id": "$bonus_type", "count": {"$sum": 1}}},
   ]
 )

it