美文网首页
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