首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >聚合查询优化Mongodb

聚合查询优化Mongodb
EN

Stack Overflow用户
提问于 2021-06-18 14:01:26
回答 1查看 72关注 0票数 2

用户模式

我一直在构建一个社交媒体应用程序,我必须编写一个返回用户的查询。用户的架构如下所示。

代码语言:javascript
复制
const userSchema = Schema(
  {
    email: {
      type: String,
      unique: true,
      required: [true, "Email is required"],
      index: true,
    },
    active: {
      type: Boolean,
      default: true,
    },
    phone: {
      type: String,
      unique: true,
      required: [true, "Phone is required"],
      index: true,
    },
    name: {
      required: true,
      type: String,
      required: [true, "Name is required"],
    },
    bio: {
      type: String,
    },
    is_admin: {
      type: Boolean,
      index: true,
      default: false,
    },
    is_merchant: {
      type: Boolean,
      index: true,
      default: false,
    },
    password: {
      type: String,
      required: [true, "Password is required"],
    },
    profile_picture: {
      type: String,
    },
    followers: [
      // meaning who has followed me
      {
        type: Types.ObjectId,
        ref: "user",
        required: false,
      },
    ],
    followings: [
      // meaning all of them who I followed
      {
        type: Types.ObjectId,
        ref: "user",
        required: false,
      },
    ],
  },
  {
    timestamps: { createdAt: "created_at", updatedAt: "updated_at" },
    toObject: {
      transform: function (doc, user) {
        delete user.password;
      },
    },
    toJSON: {
      transform: function (doc, user) {
        delete user.password;
      },
    },
  }
);

后续/后续执行

我使用如下所示的逻辑实现了后续/跟随。每次用户跟踪另一个用户。它将执行两个查询。一个是使用findOneAndUpdate({push:followee._id})更新跟随者部分,另一个是更新followee用户部分的查询。

查询响应模式

我编写了一个查询,该查询应该返回响应,并将以下响应附加到每个用户

代码语言:javascript
复制
{
  doesViewerFollowsUser: boolean // implying if person we are viewing profile of follows us 
  doesUserFollowsViewer: boolean // implying if person we are viewing profile of follows us
}

实际查询

查询必须如下所示

代码语言:javascript
复制
userModel
    .aggregate([
      {
        $match: {
          _id: {
            $in: [new Types.ObjectId(userId), new Types.ObjectId(viewerId)],
          },
        },
      },

      {
        $addFields: {
          order: {
            $cond: [
              {
                $eq: ["$_id", new Types.ObjectId(viewerId)], // testing for viewer
              },
              2,
              1,
            ],
          },
        },
      },
      {
        $group: {
          _id: 0,
          subjectFollowings: {
            $first: "$followings",
          },
          viewerFollowings: {
            $last: "$followings",
          },
          viewerFollowers: {
            $last: "$followers",
          },
        },
      },
      {
        $lookup: {
          from: "users",
          localField: "subjectFollowings",
          foreignField: "_id",
          as: "subjectFollowings",
        },
      },
      {
        $project: {
          subjectFollowings: {
            $map: {
              input: "$subjectFollowings",
              as: "user",
              in: {
                $mergeObjects: [
                  "$$user",
                  {
                    doesViewerFollowsUser: {
                      $cond: [
                        {
                          $in: ["$$user._id", "$viewerFollowers"],
                        },
                        true,
                        false,
                      ],
                    },
                  },
                  {
                    doesUserFollowsViewer: {
                      $cond: [
                        {
                          $in: ["$$user._id", "$viewerFollowings"],
                        },
                        true,
                        false,
                      ],
                    },
                  },
                ],
              },
            },
          },
        },
      },
      {
        $project: {
          "subjectFollowings.followings": 0,
          "subjectFollowings.followers": 0,
          "subjectFollowings.bio": 0,
          "subjectFollowings.password": 0,
          "subjectFollowings.is_admin": 0,
          "subjectFollowings.is_merchant": 0,
          "subjectFollowings.email": 0,
          "subjectFollowings.phone": 0,
          "subjectFollowings.created_at": 0,
          "subjectFollowings.updated_at": 0,
          "subjectFollowings.__v": 0,
        },
      },
    ])

问题所在

我不认为当前的查询规模太大。此查询的最坏情况复杂性达到0(n^2) (近似)。所以,请帮我优化这个查询。

EN

回答 1

Stack Overflow用户

发布于 2021-06-19 04:36:57

问题在于您的数据建模。不能在数组中存储跟随者/跟随者,因为:

document

  • Arrays Mongodb对每个文档都有16 to的硬限制,这意味着您可以在单个查找中存储有限的数据将需要线性时间;数组越大,查询它所需的时间就越长。

您可以做的是拥有一个用户关系集合,如下所示:

代码语言:javascript
复制
follower: user id
followee: user id

然后,您可以创建一个复合索引的追随者-折叠和查询有效地检查谁跟随谁。您还可以在这里启用时间戳。为了获得用户的所有追随者,只需在followee键上创建一个索引,这也将很快解决。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68036544

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档