node.js - Mongoose:带过滤的无限滚动
问题描述
我有这两个模型:
用户.js
const UserSchema = new Schema({
profile: {
type: Schema.Types.ObjectId,
ref: "profiles",
},
following: [
{
type: Schema.Types.ObjectId,
ref: "users",
},
],
});
module.exports = User = mongoose.model("users", UserSchema);
Profile.js
const ProfileSchema = new Schema({
videoURL: {
type: String,
},
});
module.exports = Profile = mongoose.model("profiles", ProfileSchema);
下面是一个User
文档示例:
{
"following": [
{
"profile":{
"videoURL":"video_url_1"
}
},
{
"profile":{
"videoURL":"video_url_2"
}
},
{
"profile":{}
},
{
"profile":{
"videoURL":"video_url_3"
}
},
{
"profile":{
"videoURL":"video_url_4"
}
},
{
"profile":{
"videoURL":"video_url_5"
}
},
{
"profile":{}
},
{
"profile":{
"videoURL":"video_url_6"
}
}
]
}
我正在尝试实现连接用户跟随的用户视频的无限滚动。
这意味着,我将不得不过滤 user.following.profile.videoURL WHERE videoURL
假设,我将通过两个视频加载两个视频:
- 响应 1:["video_url_1","video_url_2"]
- 响应 2:["video_url_3","video_url_4"]
- 响应 3:["video_url_5","video_url_6"]
通常,无限滚动很容易,因为我只需按存储顺序 2 x 2 加载文档,而无需对任何字段进行过滤。
示例:在无限滚动中两两显示关注的用户
User.findById(user_id).populate({
path: "following",
options: {
skip: 2 * page,
limit: 2,
},
});
但是,现在我必须对每个 follow_user.profile.video 执行过滤,然后两个两个返回。而且我看不到如何同时执行过滤和无限滚动。
注意:根据文档:
一般来说,没有办法根据故事作者的属性制作 populate() 过滤故事。例如,以下查询不会返回任何结果,即使作者已填充。
const story = await Story.
findOne({ 'author.name': 'Ian Fleming' }).
populate('author').
exec();
story; // null
所以我想,我没有办法使用 populate 来过滤user.followers
,基于每个user.follower.profile.videoURL
解决方案
我不确定填充方法是否可行,但您可以尝试聚合管道,
$match
user_id
(健康)状况$lookup
集合中的聚合管道users
用于以下操作$match
以下身份条件$lookup
profile
为_following.profile
$match
videoURL
应该存在$project
显示profile
字段并使用获取第一个元素$arrayElemAt
$slice
做分页following
let page = 0;
let limit = 2;
let skip = limit * page;
User.aggregate([
{ $match: { _id: mongoose.Types.ObjectId(user_id) } },
{
$lookup: {
from: "users",
let: { following: "$following" },
pipeline: [
{ $match: { $expr: { $in: ["$_id", "$$following"] } } },
{
$lookup: {
from: "profiles",
localField: "profile",
foreignField: "_id",
as: "profile"
}
},
{ $match: { "profile.videoURL": { $exists: true } } },
{
$project: {
profile: { $arrayElemAt: ["$profile", 0] }
}
}
],
as: "following"
}
},
{
$addFields: {
following: {
$slice: ["$following", skip, limit]
}
}
}
])
建议:
您可以改进架构设计,
- 删除配置文件模式并在用户集合中添加配置文件对象,因此您可以使用填充方法轻松实现您的要求,
- 将匹配条件放在以下填充
videoURL
中
const UserSchema = new Schema({
profile: {
type: {
videoURL: {
type: String
}
}
},
following: [
{
type: Schema.Types.ObjectId,
ref: "users"
}
]
});
module.exports = User = mongoose.model("users", UserSchema);
User.findById(user_id).populate({
path: "following",
match: {
"profile.videoURL": { $ne: null }
},
options: {
skip: 2 * page,
limit: 2,
}
});
推荐阅读
- orm - 如何使用 .net core 3 库项目从本地计算机连接到服务器上现有的 MSSQL 数据库
- mysql - 如何动态更新 SQL 字符串?
- reactjs - 从 Firebase 实时数据库中获取数据,React Native (expo)
- javascript - 如何从 CKEditor 中的 SpecialChar 插件中删除字符?
- javascript - 将卡路里跟踪应用程序转换为 ES6 类
- javascript - Spark AR 最新更新后,EACCES 权限被拒绝错误
- ios - iOS中的异步操作是否会在内部创建一个新线程并为其分配任务?
- php - 将mysql表的行值合并为数组值
- java - 二叉树广度优先搜索算法
- php - 如何按int对multiD数组进行排序