mongoose关联查询

0

mongoDB 是一个文档型数据库,在数据关系简单的情况下,可以通过文档内嵌,一些简单的数据关联写进同一个文档里,这种情况就比 MySQL 方便。但是并不是所有情况都适合使用内嵌来解决, 一旦数据达到一定规模,查询起来是相当不便的。比如经常遇到的 user-post-comment 这种一对n多,就用 populate 比较方便了

1. Schema

以user-post 一对多为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const mongoose = require('mongoose')
mongoose.connect('mongodb://localhost:27017/test');
const Shema = mongoose.Shema;
const ObjectId = Schema.Types.ObjectId;
var Post_Shema = new Shema({
user: { // post对应一个user
type: ObjectId, // 保存的只是user的objectId
ref: 'User' // 关联User model, 此处省略User细节
},
comment: [{ // post对应多个评论,故用数组
type: objectId,
ref: 'Comment' // 关联
}]
...
})
Post_Shema.index({ user:1 }) // 设置索引,查询优化
const Post = mongoose.model('Post', Post_Shema); // Shema绑定model
module.exposts = Post;

关于 Shema 部分就基本完成了。需要了解 Shema Model 之间的关系可参考 mongoose-Shema官方文档

2.使用populate

model已经写好了,增删查改就非常方便了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const Post = require('./Post')
async () => {
// 省略了捕捉异常
var post = await Post.find([condition],... )
.populate([ // 可传一个对象或对象数组
{
path: 'user', // post_schema 里的字段 已 ref 了 User model
select: 'A B C' // 选择要显示的字段
},
...
]);
console.log(post);
}

log 出来的数据可以发现是一份内嵌文档数组,使用 findByid 同理。需要注意的是 mongoDB在自动维护 CreatedAt 和 updatedAt 的字段时,采用的是格林威治时间,我使用 moment 来处理的:

1
data.createdAt = moment(data.createdAt).format('YYYY-MM-DD HH:mm:ss'); // 格式化时间

3.后记

事实上,我花了比较长的时间去了解 mongoose 怎样去写,因为文档是全英的,需要仔细看,去理解。相比与之前用 mongoSkin, 再也不用担心瞎搞了,同时 mongoose 有相当完备的 Validation, 比较有利于维护。