【问题标题】:Mongoose: Infinite scroll with filteringMongoose:带过滤的无限滚动
【发布时间】:2021-07-05 04:43:06
【问题描述】:

我有这两个模型:

用户.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 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 执行过滤,然后两个两个返回。而且我看不到如何同时执行BOTH过滤和无限滚动。


注意:根据documentation

一般来说,没有办法根据故事作者的属性使 populate() 过滤故事。例如,以下查询不会返回任何结果,即使作者已填充。

const story = await Story.
  findOne({ 'author.name': 'Ian Fleming' }).
  populate('author').
  exec();
story; // null

所以我想,我没有办法使用填充来过滤基于user.followers,基于每个user.follower.profile.videoURL

【问题讨论】:

  • 你能解释一下你想做什么样的过滤吗?
  • 我的错,我将不得不过滤 user.following.profile.videoURL WHERE videoURL 存在

标签: node.js mongodb mongoose nosql mern


【解决方案1】:

所以你想要的是无限滚动的表格和:

您可以选择给定的方法来解决您的问题

  1. 将数据(第一页)加载到网格中。
  2. 在列上设置过滤器。
  3. 再次加载数据,这次使用过滤器。

【讨论】:

  • 我没明白你的意思。
【解决方案2】:

我不确定是否可以使用填充方法,但您可以尝试聚合管道,

  • $matchuser_id条件
  • $lookupusers 集合中的聚合管道供关注
  • $match以下id条件
  • $lookupprofilefollowing.profile
  • $match videoURL 应该存在
  • $project 显示 profile 字段并使用 $arrayElemAt 获取第一个元素
  • $slicefollowing 中进行分页
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]
      }
    }
  }
])

Playground


建议:

您可以改进架构设计,

  • 删除配置文件架构并在用户集合中添加配置文件对象,因此您可以使用填充方法轻松实现您的要求,
  • 将匹配条件放在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,
  }
});

【讨论】:

  • 您发布的内容可以通过填充来实现。问题是当我在 profile.videoURL 上添加过滤时,我没有找到使用填充的方法。而且你没有在你的聚合解决方案中提到它。
  • 我告诉过你这是过滤条件“user.following.profile.videoURL WHERE videoURL exists”。我认为您提出的建议将从以下数组返回前两个用户,并且只会使用过滤条件填充配置文件,然后是后两个用户,依此类推。但是,我只希望它从以下数组中返回用户 WHERE following.profile.videoURL EXISTS。
  • 我查看了使用填充但不可能,我已根据您的填充查询更新了聚合查询。
  • 我已经添加了一个建议,如果您只是计划并开始您的开发,您可以改进这些东西,nosql 规则是避免更多的收集,尽量管理更少的收集。并避免加入。
  • 很抱歉,我真的没有得到你的建议以及它如何适用于这里。
猜你喜欢
  • 2015-01-29
  • 1970-01-01
  • 2013-12-01
  • 1970-01-01
  • 2012-10-18
  • 1970-01-01
  • 1970-01-01
  • 2012-02-27
  • 2020-03-01
相关资源
最近更新 更多