美文网首页
mongo回顾(八:聚合查询二)

mongo回顾(八:聚合查询二)

作者: supremecsp | 来源:发表于2021-04-14 18:21 被阅读0次

    上一篇简单的介绍了mongo的聚合查询,并举例了match与lookup的使用,今天的话继续介绍聚合查询与MongoDB Compass怎么查询聚合操作。

    $replaceRoot
    用指定的文档替换执行的文档,替换的字段包括_id

    { $replaceRoot: { newRoot: <replacementDocument> } }

    如果replacementDocument在文档中的数据不存在,则会解析出错

    db.collection.insertMany([
       { "_id": 1, "name" : { "first" : "John", "last" : "Backus" } },
       { "_id": 2, "name" : { "first" : "John", "last" : "McCarthy" } },
       { "_id": 3, "name": { "first" : "Grace", "last" : "Hopper" } },
       { "_id": 4, "firstname": "Ole-Johan", "lastname" : "Dahl" },
    ])
    

    以下$replaceRoot操作将失败,因为其中一个文档没有该name字段

    db.collection.aggregate([
       { $replaceRoot: { newRoot: "$name" } }
    ])
    

    为了避免这种情况,可以指定一个自定义文档数据

    db.collection.aggregate([
       { $replaceRoot: { newRoot: { $mergeObjects: [ { _id: "$_id", first: "", last: "" }, "$name" ] } } }
    ])
    
    //result
       { "_id": 1,  "first" : "John", "last" : "Backus"  }
       { "_id": 2,  "first" : "John", "last" : "McCarthy" }
       { "_id": 3,  "first" : "Grace", "last" : "Hopper"}
       { "_id": 4, "first" : "", "last" : ""};
    

    或者replaceRoot前用match过滤掉不匹配的数据

    db.collection.aggregate([
       { $match: { name : { $exists: true, $not: { $type: "array" }, $type: "object" } } },
       { $replaceRoot: { newRoot: "$name" } }
    ])
    //result
       { "first" : "John", "last" : "Backus"  }
       { "first" : "John", "last" : "McCarthy" }
       { "first" : "Grace", "last" : "Hopper"}
    

    或者使用$ifNull指定name

    $ifNull如果表达式的计算结果为空值,包括未定义值或缺少字段的实例,则返回替换表达式的值

    db.collection.aggregate([
       { $replaceRoot: { newRoot: { $ifNull: [ "$name", { _id: "$_id", first: "", last: ""} ] } } }
    ])
    
    //result
       { "first" : "John", "last" : "Backus"  }
       { "first" : "John", "last" : "McCarthy" }
       { "first" : "Grace", "last" : "Hopper"}
       {  "_id": 4, "first" : "", "last" : ""};
    

    replaceRoot可以在replacementDocument节点创建一个新的文档用来替换原文档

    db.contacts.insertMany([
      { "_id" : 1, "first_name" : "Gary", "last_name" : "Sheffield", "city" : "New York" },
      { "_id" : 2, "first_name" : "Nancy", "last_name" : "Walker", "city" : "Anaheim" },
      { "_id" : 3, "first_name" : "Peter", "last_name" : "Sumner", "city" : "Toledo" },
    ])
    
    db.contacts.aggregate( [
       {
          $replaceRoot: {
             newRoot: {
                full_name: {
                   $concat : [ "$first_name", " ", "$last_name" ]
                }
             }
          }
       }
    ] )
    //result
    { "full_name" : "Gary Sheffield" }
    { "full_name" : "Nancy Walker" }
    { "full_name" : "Peter Sumner" }
    

    replaceRoot配合mergeObjects可以补充文档数据

    $mergeObjects:将多个文档合并为一个文档,不能单独出现,配合$group,$replaceRoot等出现


    mergeObjects.png
    db.orders.insert([
      { "_id" : 1, "item" : "abc", "price" : 12, "ordered" : 2 },
      { "_id" : 2, "item" : "jkl", "price" : 20, "ordered" : 1 }
    ])
    
    db.items.insert([
      { "_id" : 1, "item" : "abc", description: "product 1", "instock" : 120 },
      { "_id" : 2, "item" : "def", description: "product 2", "instock" : 80 },
      { "_id" : 3, "item" : "jkl", description: "product 3", "instock" : 60 },
      { "_id" : 4, "item" : "abc", description: "product 4", "instock" : 20},
    ])
    
    db.orders.aggregate([
       {
          $lookup: {
             from: "items",
             localField: "item",    // field in the orders collection
             foreignField: "item",  // field in the items collection
             as: "fromItems"
          }
       },
       {
          $replaceRoot: { newRoot: { $mergeObjects: [ { $arrayElemAt: [ "$fromItems", 0 ] }, "$$ROOT" ] } }
       },
       { $project: { fromItems: 0 } }
    ])
    //redsult
    { "_id" : 1, "item" : "abc", "description" : "product 1", "instock" : 120, "price" : 12, "ordered" : 2 }
    { "_id" : 2, "item" : "jkl", "description" : "product 3", "instock" : 60, "price" : 20, "ordered" : 1 }
    

    $arrayElemAt返回指定数组索引处的元素。正数索引从头开始,负数从尾开始,超过数组界限不返回值

    接下来在MongoDB Compass中执行这个操作,Compass可以展示每一步的结果,使用也比较方便


    result.png

    第一步左连接后,fromItems是个数组,_id为1的文档fromItems包含两个对象;
    第二步将数组的第一个对象与根数据合并,可以看到根文档多了description,instock字段;
    第三步将fromItems在返回结果去除

    总结:这一篇介绍了replaceRoot,ifNull,mergeObjects,arrayElemAt聚合操作的用法并简单演示了MongoDB Compass,下一篇继续其他的聚合查询操作

    相关文章

      网友评论

          本文标题:mongo回顾(八:聚合查询二)

          本文链接:https://www.haomeiwen.com/subject/aykllltx.html