猫鼬:无限滚动过滤
Mongoose: Infinite scroll with filtering
我有这两个型号:
User.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"
}
}
]
}
我正在尝试实现连接用户关注的用户视频的无限滚动。
This means, I will have to filter user.following.profile.videoURL
WHERE videoURL exists
假设,我将通过两个视频加载两个视频:
- 响应 1:[""video_url_1","video_url_2"]
- 响应 2:["video_url_3","video_url_4"]
- 响应 3:[""video_url_5","video_url_6"]
通常,无限滚动很容易,因为我只需要按存储顺序 2 乘 2 地加载文档,而无需在任何字段上进行过滤。
示例:无限滚动两两显示关注的用户
User.findById(user_id).populate({
path: "following",
options: {
skip: 2 * page,
limit: 2,
},
});
但是,现在我必须对每个 followed_user.profile.video 和 return 两个两个地执行过滤。而且我不知道如何同时执行 BOTH 过滤和无限滚动。
注意: 根据 documentation:
In general, there is no way to make populate() filter stories based on properties of the story's author. For example, the below query won't return any results, even though author is populated.
const story = await Story.
findOne({ 'author.name': 'Ian Fleming' }).
populate('author').
exec();
story; // null
所以我想,我没有办法使用填充来过滤基于 user.followers
,基于每个 user.follower.profile.videoURL
所以你想要的是 table 无限滚动和:
您可以选择给定的方法来解决您的问题 :
- 将数据(第一页)加载到网格中。
- 在列上设置过滤器
- 再次加载数据,这次使用过滤器。
我不确定填充方法是否可行,但您可以尝试聚合管道,
$match
user_id
条件
$lookup
在 users
集合中使用聚合管道以供后续
$match
以下id条件
$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]
}
}
}
])
建议:
您可以改进架构设计,
- 删除配置文件架构并在用户集合中添加配置文件对象,这样您就可以使用填充方法轻松实现您的要求,
- 将匹配条件放在下面 populate for
videoURL
exists
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,
}
});
我有这两个型号:
User.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"
}
}
]
}
我正在尝试实现连接用户关注的用户视频的无限滚动。
This means, I will have to filter user.following.profile.videoURL WHERE videoURL exists
假设,我将通过两个视频加载两个视频:
- 响应 1:[""video_url_1","video_url_2"]
- 响应 2:["video_url_3","video_url_4"]
- 响应 3:[""video_url_5","video_url_6"]
通常,无限滚动很容易,因为我只需要按存储顺序 2 乘 2 地加载文档,而无需在任何字段上进行过滤。
示例:无限滚动两两显示关注的用户
User.findById(user_id).populate({
path: "following",
options: {
skip: 2 * page,
limit: 2,
},
});
但是,现在我必须对每个 followed_user.profile.video 和 return 两个两个地执行过滤。而且我不知道如何同时执行 BOTH 过滤和无限滚动。
注意: 根据 documentation:
In general, there is no way to make populate() filter stories based on properties of the story's author. For example, the below query won't return any results, even though author is populated.
const story = await Story.
findOne({ 'author.name': 'Ian Fleming' }).
populate('author').
exec();
story; // null
所以我想,我没有办法使用填充来过滤基于 user.followers
,基于每个 user.follower.profile.videoURL
所以你想要的是 table 无限滚动和:
您可以选择给定的方法来解决您的问题 :
- 将数据(第一页)加载到网格中。
- 在列上设置过滤器
- 再次加载数据,这次使用过滤器。
我不确定填充方法是否可行,但您可以尝试聚合管道,
$match
user_id
条件$lookup
在users
集合中使用聚合管道以供后续$match
以下id条件$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]
}
}
}
])
建议:
您可以改进架构设计,
- 删除配置文件架构并在用户集合中添加配置文件对象,这样您就可以使用填充方法轻松实现您的要求,
- 将匹配条件放在下面 populate for
videoURL
exists
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,
}
});