如何使用 nodejs 在 mongoose 中进行多级填充
How to do multilevel populate in mongoose with nodejs
我想为博客 post 创建数据,其中包含 post 的列表、其相关评论、回复以及用户详细信息。
我试过嵌套填充,但只能做一层。就像我得到评论对象一样,我需要在其中填充回复和用户 ID。在回复中,我需要填充 userId 和 repliesCount。在此,仅填充最后给出的 returns 填充的数据其他字段仅列出 ID。
posts.model.js:
const mongoose = require('mongoose')
var ObjectId = mongoose.Schema.Types.ObjectId
let PostsSchema = new mongoose.Schema({
userId: {
type: ObjectId,
ref: 'User'
},
celebrityId: {
type: ObjectId,
ref: 'CelebrityDetails'
},
type: {
type: Number,
default: 1
},
isForwarded: {
type: Number,
default: 0
},
originalPostId: {
type: ObjectId,
default: null
},
title: {
type: String
},
description: {
type: String
},
status: {
type: Number,
default: 1
}
}, {
timestamps: true,
collection: 'fan_posts'
})
PostsSchema.virtual('isMyPost', {
ref: 'User',
localField: 'userId',
foreignField: '_id',
count: true
})
PostsSchema.virtual('comments', {
ref: 'PostComment',
localField: '_id',
foreignField: 'postId'
})
PostsSchema.virtual('commentCount', {
ref: 'PostComment',
localField: '_id',
foreignField: 'postId',
count: true
})
PostsSchema.set('toObject', { virtuals: true })
PostsSchema.set('toJSON', { virtuals: true })
const Posts = mongoose.model('Posts', PostsSchema)
Posts.consts = {
STATUS_INACTIVE: 0,
STATUS_ACTIVE: 1,
STATUS_DELETED: 2,
IS_FORWARDED: 1,
TYPE_TEXT: 1,
TYPE_IMAGE: 2,
TYPE_VIDEO: 3,
TYPE_ASK_TEXT: 4,
TYPE_ASK_IMAGE: 5,
TYPE_RATING: 6
}
module.exports = Posts
comments.model.js
const mongoose = require('mongoose')
var ObjectId = mongoose.Schema.Types.ObjectId
let PostCommentSchema = new mongoose.Schema({
userId: {
type: ObjectId,
ref: 'User'
},
postId: {
type: ObjectId,
ref: 'FanPosts'
},
comment: {
type: String
},
isReply: {
type: Number,
default: 0
},
parentCommentId: {
type: ObjectId,
ref: 'PostComment'
}
}, {
timestamps: true,
collection: 'post_comment'
})
PostCommentSchema.set('toObject', { virtuals: true })
PostCommentSchema.set('toJSON', { virtuals: true })
PostCommentSchema.virtual('replies', {
ref: 'PostComment',
localField: '_id',
foreignField: 'parentCommentId'
})
PostCommentSchema.virtual('repliesCount', {
ref: 'PostComment',
localField: '_id',
foreignField: 'parentCommentId',
count: true,
justOne: true
})
const PostComment = mongoose.model('PostComment', PostCommentSchema)
PostComment.consts = {
TYPE_NOT_REPLY: 0,
TYPE_REPLY: 1
}
module.exports = PostComment
查询:
Posts.find({celebrityId: celebrityId, status: Posts.consts.STATUS_ACTIVE})
.populate({ path: 'userId', select: 'fmId fullName' })
.populate({ path: 'isMyPost', match:{_id: userId} })
.populate({ path: 'comments', match: {isReply: PostComment.consts['TYPE_NOT_REPLY']}, populate: {path: 'userId', select: 'fmId fullName'}, populate: {path: 'replies', match: {isReply: PostComment.consts['TYPE_REPLY']}, populate: {path: 'userId', select: 'fmId fullName'} } })
.populate({ path: 'commentCount'})
.exec(function(err, posts){
if (err) return res.send({status: status.codes.http['serverError'], message: err})
return res.send({status: status.codes.http['success'], posts: posts})
})
结果:
{
"status": 200,
"posts": [
{
"type": 1,
"isForwarded": 0,
"originalPostId": null,
"status": 1,
"_id": "5d2b16519788076fafe7700c",
"celebrityId": "5d167ca099a55c2d2494dcf8",
"post": "hi how are you",
"userId": {
"_id": "5d167a397213b127aafb48f3",
"fmId": "FM499KNWDL",
"fullName": "Mohideen Abubucker"
},
"createdAt": "2019-07-14T11:47:29.863Z",
"updatedAt": "2019-07-14T11:47:29.863Z",
"__v": 0,
"isMyPost": 1,
"comments": [
{
"isReply": 0,
"_id": "5d33721a12aba934e6520f2d",
"userId": "5d167a397213b127aafb48f3",
"postId": "5d2b16519788076fafe7700c",
"comment": "comment 1",
"createdAt": "2019-07-20T19:57:14.747Z",
"updatedAt": "2019-07-20T19:57:14.747Z",
"__v": 0,
"replies": [
{
"isReply": 1,
"_id": "5d33724e12aba934e6520f2e",
"userId": {
"_id": "5d167a397213b127aafb48f3",
"fmId": "FM499KNWDL",
"fullName": "Mohideen Abubucker"
},
"postId": "5d2b16519788076fafe7700c",
"comment": "comment 1",
"parentCommentId": "5d33721a12aba934e6520f2d",
"createdAt": "2019-07-20T19:58:06.286Z",
"updatedAt": "2019-07-20T19:58:06.286Z",
"__v": 0,
"id": "5d33724e12aba934e6520f2e"
}
],
"id": "5d33721a12aba934e6520f2d"
}
],
"commentCount": 2,
"id": "5d2b16519788076fafe7700c"
},
]
}
我需要在 comments 对象中填充 userId,并将 repliesCount 添加到 replies 对象。
问题是,我只能填充一列。在查询中,如果您看到我会为 userId 和回复提供填充。由于回复是最后一个,所以我正在获取回复数据。
我不知道如何填充回复和用户 ID
预计:
{
"status": 200,
"posts": [
{
"type": 1,
"isForwarded": 0,
"originalPostId": null,
"status": 1,
"_id": "5d2b16519788076fafe7700c",
"celebrityId": "5d167ca099a55c2d2494dcf8",
"post": "hi how are you",
"userId": {
"_id": "5d167a397213b127aafb48f3",
"fmId": "FM499KNWDL",
"fullName": "Mohideen Abubucker"
},
"createdAt": "2019-07-14T11:47:29.863Z",
"updatedAt": "2019-07-14T11:47:29.863Z",
"__v": 0,
"isMyPost": 1,
"comments": [
{
"isReply": 0,
"_id": "5d33721a12aba934e6520f2d",
"userId": {
"_id": "5d167a397213b127aafb48f3",
"fmId": "FM499KNWDL",
"fullName": "Mohideen Abubucker"
},
"postId": "5d2b16519788076fafe7700c",
"comment": "comment 1",
"createdAt": "2019-07-20T19:57:14.747Z",
"updatedAt": "2019-07-20T19:57:14.747Z",
"__v": 0,
"replies": [
{
"isReply": 1,
"_id": "5d33724e12aba934e6520f2e",
"userId": {
"_id": "5d167a397213b127aafb48f3",
"fmId": "FM499KNWDL",
"fullName": "Mohideen Abubucker"
},
"postId": "5d2b16519788076fafe7700c",
"comment": "comment 1",
"parentCommentId": "5d33721a12aba934e6520f2d",
"createdAt": "2019-07-20T19:58:06.286Z",
"updatedAt": "2019-07-20T19:58:06.286Z",
"__v": 0,
"id": "5d33724e12aba934e6520f2e",
"repliesCount": 1
}
],
"id": "5d33721a12aba934e6520f2d"
}
],
"commentCount": 2,
"id": "5d2b16519788076fafe7700c"
},
]
}
这里的问题:
.populate({ path: 'comments', match: {isReply: PostComment.consts['TYPE_NOT_REPLY']}, populate: {path: 'userId', select: 'fmId fullName'}, populate: {path: 'replies', match: {isReply: PostComment.consts['TYPE_REPLY']}, populate: {path: 'userId', select: 'fmId fullName'} } })
您的填充参数:
{
path: 'comments',
match: {
isReply: PostComment.consts['TYPE_NOT_REPLY']
},
populate: {
path: 'userId',
select: 'fmId fullName'
},
populate: {
path: 'replies',
match: {
isReply: PostComment.consts['TYPE_REPLY']
},
populate: {
path: 'userId',
select: 'fmId fullName'
}
}
}
对象字面量是键值映射的一种形式,因此您不能在对象的单个级别中具有相同 value 的多个键。
您在对象的单个级别上有 2 个具有 值 "populate" 的键,看起来只有最后一个保留在对象中。
你可以在这里看到:https://jsfiddle.net/32oe6w8y/1/
查看 mongoose 文档,我确定他们有处理这个问题的机制(填充可能需要一个数组。)
美国东部时间:
基于此,您可以将数组传递给填充:
这可能是您问题的解决方案。
修复了有问题的填充参数:
{
path: 'comments',
match: {
isReply: PostComment.consts['TYPE_NOT_REPLY']
},
populate: [{
path: 'userId',
select: 'fmId fullName'
},{
path: 'replies',
match: {
isReply: PostComment.consts['TYPE_REPLY']
},
populate: {
path: 'userId',
select: 'fmId fullName'
}
}]
}
我想为博客 post 创建数据,其中包含 post 的列表、其相关评论、回复以及用户详细信息。
我试过嵌套填充,但只能做一层。就像我得到评论对象一样,我需要在其中填充回复和用户 ID。在回复中,我需要填充 userId 和 repliesCount。在此,仅填充最后给出的 returns 填充的数据其他字段仅列出 ID。
posts.model.js:
const mongoose = require('mongoose')
var ObjectId = mongoose.Schema.Types.ObjectId
let PostsSchema = new mongoose.Schema({
userId: {
type: ObjectId,
ref: 'User'
},
celebrityId: {
type: ObjectId,
ref: 'CelebrityDetails'
},
type: {
type: Number,
default: 1
},
isForwarded: {
type: Number,
default: 0
},
originalPostId: {
type: ObjectId,
default: null
},
title: {
type: String
},
description: {
type: String
},
status: {
type: Number,
default: 1
}
}, {
timestamps: true,
collection: 'fan_posts'
})
PostsSchema.virtual('isMyPost', {
ref: 'User',
localField: 'userId',
foreignField: '_id',
count: true
})
PostsSchema.virtual('comments', {
ref: 'PostComment',
localField: '_id',
foreignField: 'postId'
})
PostsSchema.virtual('commentCount', {
ref: 'PostComment',
localField: '_id',
foreignField: 'postId',
count: true
})
PostsSchema.set('toObject', { virtuals: true })
PostsSchema.set('toJSON', { virtuals: true })
const Posts = mongoose.model('Posts', PostsSchema)
Posts.consts = {
STATUS_INACTIVE: 0,
STATUS_ACTIVE: 1,
STATUS_DELETED: 2,
IS_FORWARDED: 1,
TYPE_TEXT: 1,
TYPE_IMAGE: 2,
TYPE_VIDEO: 3,
TYPE_ASK_TEXT: 4,
TYPE_ASK_IMAGE: 5,
TYPE_RATING: 6
}
module.exports = Posts
comments.model.js
const mongoose = require('mongoose')
var ObjectId = mongoose.Schema.Types.ObjectId
let PostCommentSchema = new mongoose.Schema({
userId: {
type: ObjectId,
ref: 'User'
},
postId: {
type: ObjectId,
ref: 'FanPosts'
},
comment: {
type: String
},
isReply: {
type: Number,
default: 0
},
parentCommentId: {
type: ObjectId,
ref: 'PostComment'
}
}, {
timestamps: true,
collection: 'post_comment'
})
PostCommentSchema.set('toObject', { virtuals: true })
PostCommentSchema.set('toJSON', { virtuals: true })
PostCommentSchema.virtual('replies', {
ref: 'PostComment',
localField: '_id',
foreignField: 'parentCommentId'
})
PostCommentSchema.virtual('repliesCount', {
ref: 'PostComment',
localField: '_id',
foreignField: 'parentCommentId',
count: true,
justOne: true
})
const PostComment = mongoose.model('PostComment', PostCommentSchema)
PostComment.consts = {
TYPE_NOT_REPLY: 0,
TYPE_REPLY: 1
}
module.exports = PostComment
查询:
Posts.find({celebrityId: celebrityId, status: Posts.consts.STATUS_ACTIVE})
.populate({ path: 'userId', select: 'fmId fullName' })
.populate({ path: 'isMyPost', match:{_id: userId} })
.populate({ path: 'comments', match: {isReply: PostComment.consts['TYPE_NOT_REPLY']}, populate: {path: 'userId', select: 'fmId fullName'}, populate: {path: 'replies', match: {isReply: PostComment.consts['TYPE_REPLY']}, populate: {path: 'userId', select: 'fmId fullName'} } })
.populate({ path: 'commentCount'})
.exec(function(err, posts){
if (err) return res.send({status: status.codes.http['serverError'], message: err})
return res.send({status: status.codes.http['success'], posts: posts})
})
结果:
{
"status": 200,
"posts": [
{
"type": 1,
"isForwarded": 0,
"originalPostId": null,
"status": 1,
"_id": "5d2b16519788076fafe7700c",
"celebrityId": "5d167ca099a55c2d2494dcf8",
"post": "hi how are you",
"userId": {
"_id": "5d167a397213b127aafb48f3",
"fmId": "FM499KNWDL",
"fullName": "Mohideen Abubucker"
},
"createdAt": "2019-07-14T11:47:29.863Z",
"updatedAt": "2019-07-14T11:47:29.863Z",
"__v": 0,
"isMyPost": 1,
"comments": [
{
"isReply": 0,
"_id": "5d33721a12aba934e6520f2d",
"userId": "5d167a397213b127aafb48f3",
"postId": "5d2b16519788076fafe7700c",
"comment": "comment 1",
"createdAt": "2019-07-20T19:57:14.747Z",
"updatedAt": "2019-07-20T19:57:14.747Z",
"__v": 0,
"replies": [
{
"isReply": 1,
"_id": "5d33724e12aba934e6520f2e",
"userId": {
"_id": "5d167a397213b127aafb48f3",
"fmId": "FM499KNWDL",
"fullName": "Mohideen Abubucker"
},
"postId": "5d2b16519788076fafe7700c",
"comment": "comment 1",
"parentCommentId": "5d33721a12aba934e6520f2d",
"createdAt": "2019-07-20T19:58:06.286Z",
"updatedAt": "2019-07-20T19:58:06.286Z",
"__v": 0,
"id": "5d33724e12aba934e6520f2e"
}
],
"id": "5d33721a12aba934e6520f2d"
}
],
"commentCount": 2,
"id": "5d2b16519788076fafe7700c"
},
]
}
我需要在 comments 对象中填充 userId,并将 repliesCount 添加到 replies 对象。
问题是,我只能填充一列。在查询中,如果您看到我会为 userId 和回复提供填充。由于回复是最后一个,所以我正在获取回复数据。
我不知道如何填充回复和用户 ID
预计:
{
"status": 200,
"posts": [
{
"type": 1,
"isForwarded": 0,
"originalPostId": null,
"status": 1,
"_id": "5d2b16519788076fafe7700c",
"celebrityId": "5d167ca099a55c2d2494dcf8",
"post": "hi how are you",
"userId": {
"_id": "5d167a397213b127aafb48f3",
"fmId": "FM499KNWDL",
"fullName": "Mohideen Abubucker"
},
"createdAt": "2019-07-14T11:47:29.863Z",
"updatedAt": "2019-07-14T11:47:29.863Z",
"__v": 0,
"isMyPost": 1,
"comments": [
{
"isReply": 0,
"_id": "5d33721a12aba934e6520f2d",
"userId": {
"_id": "5d167a397213b127aafb48f3",
"fmId": "FM499KNWDL",
"fullName": "Mohideen Abubucker"
},
"postId": "5d2b16519788076fafe7700c",
"comment": "comment 1",
"createdAt": "2019-07-20T19:57:14.747Z",
"updatedAt": "2019-07-20T19:57:14.747Z",
"__v": 0,
"replies": [
{
"isReply": 1,
"_id": "5d33724e12aba934e6520f2e",
"userId": {
"_id": "5d167a397213b127aafb48f3",
"fmId": "FM499KNWDL",
"fullName": "Mohideen Abubucker"
},
"postId": "5d2b16519788076fafe7700c",
"comment": "comment 1",
"parentCommentId": "5d33721a12aba934e6520f2d",
"createdAt": "2019-07-20T19:58:06.286Z",
"updatedAt": "2019-07-20T19:58:06.286Z",
"__v": 0,
"id": "5d33724e12aba934e6520f2e",
"repliesCount": 1
}
],
"id": "5d33721a12aba934e6520f2d"
}
],
"commentCount": 2,
"id": "5d2b16519788076fafe7700c"
},
]
}
这里的问题:
.populate({ path: 'comments', match: {isReply: PostComment.consts['TYPE_NOT_REPLY']}, populate: {path: 'userId', select: 'fmId fullName'}, populate: {path: 'replies', match: {isReply: PostComment.consts['TYPE_REPLY']}, populate: {path: 'userId', select: 'fmId fullName'} } })
您的填充参数:
{
path: 'comments',
match: {
isReply: PostComment.consts['TYPE_NOT_REPLY']
},
populate: {
path: 'userId',
select: 'fmId fullName'
},
populate: {
path: 'replies',
match: {
isReply: PostComment.consts['TYPE_REPLY']
},
populate: {
path: 'userId',
select: 'fmId fullName'
}
}
}
对象字面量是键值映射的一种形式,因此您不能在对象的单个级别中具有相同 value 的多个键。
您在对象的单个级别上有 2 个具有 值 "populate" 的键,看起来只有最后一个保留在对象中。
你可以在这里看到:https://jsfiddle.net/32oe6w8y/1/
查看 mongoose 文档,我确定他们有处理这个问题的机制(填充可能需要一个数组。)
美国东部时间: 基于此,您可以将数组传递给填充:
这可能是您问题的解决方案。
修复了有问题的填充参数:
{
path: 'comments',
match: {
isReply: PostComment.consts['TYPE_NOT_REPLY']
},
populate: [{
path: 'userId',
select: 'fmId fullName'
},{
path: 'replies',
match: {
isReply: PostComment.consts['TYPE_REPLY']
},
populate: {
path: 'userId',
select: 'fmId fullName'
}
}]
}