node.js - 如何根据引用的子文档值过滤 MongoDB/Mongoose 查询
问题描述
因此,我目前正在克隆一些应用程序概念(用于学习目的),并且我已经构建了一个基本的社交媒体应用程序,该应用程序具有用户、帖子,并允许用户在不想共享数据时阻止用户。但我的问题是,我可以使用引用的文档值/数据(填充用户的被阻止用户数组)来过滤掉父文档(帖子)吗?希望这是有道理的。
到目前为止,这里是模式(当然是精简的):
// User Schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const UserSchema = new Schema({
email: {
type: String,
required: [true, "Please provide an email"],
unique: true
},
password: {
type: String,
minlength: 8
},
blockedUsers: {
type: [{
type: Schema.Types.ObjectId,
ref: 'User'
}]
}
});
// Post Schema
const PostSchema = new Schema({
author: {
type: Schema.Types.ObjectId,
ref: 'User'
},
dateCreated: {
type: Date,
default: Date.now()
},
body: {
type: String,
required: true,
trim: true,
maxlength: 1200
}
});
const User = mongoose.model('User', UserSchema);
const Post = mongoose.model('Post', PostSchema);
然后我的查询到目前为止只过滤掉了子文档,并且在我的测试中将null
作者返回到我的帖子中,这不完全是我希望的功能。澄清一下,它仍然返回被查询的正确帖子,但它不填充“作者”字段,而是将作者字段设置为null
。
router.get('/p/:postID', catchAsyncErr(async (req, res, next) => {
// Find post and make sure the user requesting the post is not blocked by the author
const post = await Post.findById(req.params.postID).populate({
path: 'author',
select: 'blockedUsers',
match: {
blockedUsers: {
$ne: req.user.id // The user ID stored in the JSON Web token
}
}
});
res.status(200).json({
status: 'Success',
statusCode: 200,
message: `Post "${req.params.postID}" found`,
data: post
})
}));
我尝试使用聚合,老实说,我仍在尝试完全理解这个$lookup
概念。但我有一种奇怪的感觉,那应该是我测试更多的地方......
基本上,如果作者(用户)在“blockedUsers”列表中有请求用户,我真的想隐藏帖子并返回 404。我知道我可以使用常规的 if/else 语句来做到这一点,但我真的希望能够在查询中做到这一点。此外,如果您愿意,我希望能够在用户主页上实现同样的概念。如果他们被用户阻止,阻止他们的用户将不会在他们的提要中显示他们的帖子。
感谢您对此的任何见解!
解决方案
你可以用它aggregation pipeline
来做到这一点。您需要$lookup
加入(填充)作者并$match
过滤您的用户。
$match
与您的第一个参数非常相似find()
。
$lookup
join
如果您熟悉,则类似于SQL。
要进行设置,$lookup
您需要四个参数。
from
:哪个是您的目标集合(这里是users
)
localField
:哪个是您的外键字段名称(这里author
)
foreignField
:哪个是目标集合字段(这里_id
)
as
:加入后的名称(这里我使用author
)
这是片段:
const post = Post.aggregate([{
$match: {
_id: req.params.postID
}
},
{
$lookup: {
from: 'users',
localField: 'author',
foreignField: '_id',
as: 'author'
}
}])
那么你post.author.blockedUsers
应该工作正常。
如果要检索特定的阻塞用户,可以使用如下聚合:
const post = Post.aggregate([{
$match: {
_id: req.params.postID
}
},
{
$lookup: {
from: 'users',
'let': {authorId: "$author"},
pipeline: [{
$match: {
$expr: {
$and: [{
$eq: ['$_id', '$$authorId']
}, {
$ne: ['$blockedUsers', req.user.id]
}]
}
}
}
as: 'author'
}
}])
推荐阅读
- reactjs - Reducer:更新数组内的数组
- opencart-3 - 使用 IDE 进行 Opencart 代码编辑不起作用
- javascript - Nuxt Layout 更新每条路线的数据
- javascript - 我正在使用此代码时遇到 JSX 错误,我无法弄清楚
- haskell - 将泛型函数类型检查推断为返回类型但不是参数类型
- elasticsearch - Elasticsearch 自定义分析器
- python - 为什么我的脚本可以正常工作,当我手动执行它时,但使用 crontab 它不起作用?
- ruby-on-rails - 添加限制以验证发送到 Rails API 的 json 数据
- python - Loky-backed 并行循环不能嵌套在线程下面,设置 n_jobs=1
- jquery - jQuery 不加载整个表格