MongoDB 初探

MongoDB 初探

对于已经熟悉 MySQL 的同学来说,初次接触 MongoDB 可能会不习惯它的语法,本篇文章将通过一个简单的示例带你入门 MongoDB。

准备

对于 MongoDB 新手,可以借助 DataGrip 来学习MongoDB 语法。在 MongoDB 中实现准备好两个表 "old" 和 "new",并随意插入一些数据

db.createCollection("new")  
db.createCollection("old")

db.old.insertOne({  
id: 1,  
name: old  
})  
db.new.insertOne({  
id: 2,  
name: 13,  
goods: 1  
})
// 随意插入数据

在 DataGrip 中输入如下的 SQL 语句

select * from "new" as aleft left join "old" as bright on aleft.id = bright.id;

然后在这条语句上「右键」,选择 「Show JS Script」,会发现 DataGrip 会帮助我们将 SQL 语句转为 MongoDB 语句,接下来我们通过研究这个语句来体会 MongoDB 的基本思想

db.getSiblingDB("test").getCollection("new").aggregate([  
  {  
    $project: {"aleft": "$$ROOT", "_id": 0}  
  },  
  {  
    $lookup: {  
      localField: "aleft.id",  
      from: "old",  
      foreignField: "id",  
      as: "bright"  
    }  
  },  
  {  
    $unwind: {  
      path: "$bright",  
      preserveNullAndEmptyArrays: true  
    }  
  },  
  {  
    $replaceRoot: {  
      newRoot: {$mergeObjects: ["$aleft", "$bright", "$$ROOT"]}  
    }  
  },  
  {  
    $project: {"aleft": 0, "bright": 0}  
  }  
])

分析

aggregate

db.collection.aggregate(管道,选项) 方法参数接收一个包含了若干操作的数组,类似于 Linux 中的管道一样,对集合依次进行操作。

project

第一个操作为 $project ,这是一个映射操作

  {  
    $project: {"aleft": "$$ROOT", "_id": 0}  
  }

其中 $$ROOT 即引用顶级文档,效果是将当前文档(行)的所有数据放到 aleft 字段下。"_id": 0 代表隐藏 _id 行,当设定为 "_id": 1 时会展示 _id 行,(_id 由 MongoDB 自动生成)结果示意如下:

[  
  {  
    "aleft": {  
      "_id": {"$oid": "6247f1e253a1be11c3b88d8b"},  
      "id": 1,  
      "name": 12  
    }  
  },  
  {  
    "_id": {"$oid": "624ce445b67f62529d94a83e"}, // 当 _id: 1 时会展示 id 
    "aleft": {  
      "_id": {"$oid": "624ce445b67f62529d94a83e"},  
      "id": 2,  
      "name": 13,  
      "goods": 1  
    }  
  }  
]

lookup

第二个操作为

  {  
    $lookup: {  
      localField: "aleft.id",  
      from: "old",  
      foreignField: "id",  
      as: "bright" 
    } 
  }

顾名思义,这是一个查找操作,它根据第一步结果中的 aleft.id 字段,在 old 表中查找 id 与之相等的文档(行),并将所有匹配的结果以数组方式放在 bright 字段下,结果示意如下:

[  
  {  
    "aleft": {  
      "_id": {"$oid": "6247f1e253a1be11c3b88d8b"},  
      "id": 1,  
      "name": 12  
     },  
    "bright": [  
      {  
        "_id": {"$oid": "624ce82ab67f62529d94a84c"},  
        "id": 1,  
        "name": "haha"  
      },  
      {  
        "_id": {"$oid": "624ce867b67f62529d94a84e"},  
        "id": 1,  
        "vbsss": "haha"  
      }  
    ]  
  }
]

unwind

第三个操作为

  {  
    $unwind: {  
      path: "$bright",  
      preserveNullAndEmptyArrays: true
    } 
  } 

这个操作指明了使用 $bright 字段,这个字段是一个数组,$unwind 操作会将 $bright 中的每一个元素与 aleft 组合

[  
  {  
    "aleft": {  
      "_id": {"$oid": "6247f1e253a1be11c3b88d8b"},  
      "id": 1,  
      "name": 12  
    },  
    "bright": {  
      "_id": {"$oid": "624ce82ab67f62529d94a84c"},  
      "id": 1,  
      "name": "haha"  
     }  
  },  
  {  
    "aleft": {  
      "_id": {"$oid": "6247f1e253a1be11c3b88d8b"},  
      "id": 1,  
      "name": 12  
     },  
    "bright": {  
      "_id": {"$oid": "624ce867b67f62529d94a84e"},  
      "id": 1,  
      "vbsss": "haha"  
     }  
  }
]

至此,我们已经将两个表中关联的行组合在了一起,接下来需要将这个结构简化一下

replaceRoot

第四个操作为

  {  
    $replaceRoot: {  
      newRoot: {$mergeObjects: ["$aleft", "$bright", "$$ROOT"]}  
    }  
  },

mergeObjects

$mergeObjects 操作会将参数中元素的内容进行合并,如果有重复,后面的值会覆盖前面的值,比如下面的这个文档

  {  
    "aleft": {  
      "_id": {"$oid": "6247f1e253a1be11c3b88d8b"},  
      "id": 1,  
      "name": 12  
    },  
    "bright": {  
      "_id": {"$oid": "624ce82ab67f62529d94a84c"},  
      "id": 1,  
      "name": "haha"  
     }  
  },

执行 $mergeObjects: ["$aleft", "$bright", "$$ROOT"] 操作后结果如下

  {  
    "_id": {"$oid": "6247f1e253a1be11c3b88d8b"},  
    "aleft": {  
      "_id": {"$oid": "6247f1e253a1be11c3b88d8b"},  
      "id": 1,  
      "name": 12  
    },  
    "bright": {  
      "_id": {"$oid": "624ce82ab67f62529d94a84c"},  
      "id": 1,  
      "name": "haha"  
    },  
    "id": 1,  
    "name": "haha"  
  }

replaceRoot

$replaceRoot 将指定的文档提升到顶层,并丢弃顶层所有其他字段。

[  
  {  
    "_id": {"$oid": "6247f1e253a1be11c3b88d8b"},  
    "aleft": {  
      "_id": {"$oid": "6247f1e253a1be11c3b88d8b"},  
      "id": 1,  
      "name": 12  
    },  
    "bright": {  
      "_id": {"$oid": "624ce82ab67f62529d94a84c"},  
      "id": 1,  
      "name": "haha"  
    },  
    "id": 1,  
    "name": "haha"  
  }
]

至此,只要将 aleftbright 两个参数删掉就得到了最后的结果,操作为

  {  
    $project: {"aleft": 0, "bright": 0}  
  }

结果示意如下

[  
  {  
    "_id": {"$oid": "6247f1e253a1be11c3b88d8b"},  
    "id": 1,  
    "name": "haha"  
  }
]

其他

MongoDB 中的 JOIN 操作还是十分复杂的,与 MySQL 不同, MongoDB 中的文档结构并没有限制,所以可以采用嵌套文档的方式将本来需要关联的数据保存在一起,从而避免 JOIN 操作