簡體   English   中英

聚合查詢優化Mongodb

[英]Aggregation Query Optimization Mongodb

用戶架構

我一直在構建一個社交媒體應用程序,我必須編寫一個返回用戶用戶的查詢。 用戶的架構如下所示。

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;
      },
    },
  }
);

跟進/跟進實施

我已經使用如下所示的邏輯實現了關注/關注。 每次用戶跟隨另一個用戶。 它將執行 2 個查詢。 可以使用findOneAndUpdate({push:followee._id})和第二個查詢更新關注者關注者部分以更新關注者用戶部分。

跟隨/跟隨更新后的用戶模型

查詢響應模式

我寫了一個查詢,應該返回響應,並附加到每個用戶的以下響應

{
  doesViewerFollowsUser: boolean // implying if person we are viewing profile of follows us 
  doesUserFollowsViewer: boolean // implying if person we are viewing profile of follows us
}

實際查詢

查詢必須如下所示


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)(大約) 所以,請幫我優化這個查詢。

問題在於您的數據建模。 您不應該將關注者/關注者存儲在數組中,因為:

  1. Mongodb 對每個文檔有 16mb 的硬限制,這意味着您可以在單個文檔中存儲有限的數據
  2. 數組查找需要線性時間; 數組越大,查詢它所需的時間就越長。

您可以做的是為用戶關系建立一個集合,如下所示:

follower: user id
followee: user id

然后,您可以在 follower-followee 上創建復合索引並有效查詢以檢查誰跟隨誰。 您還可以在此處啟用時間戳。 為了獲得用戶的所有關注者,只需在 followee 鍵上創建一個索引,這也將很快解決

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM