MongoDB按辅助查找表排序

Ert*_*maa 6 mongodb

我有一个约会应用程序,我将所有潜在的Match对象存储在MongoDB中(当用户向左或向右滑动时会发生Match对象):

{
   uid1: <userid1>,
   uid2: <userid2>,

   uid1action: <L|R|E> (left/right/empty, based what the user1 has done),
   uid2action: <L|R|E> (left/right/empty, based what the user2 has done),
}
Run Code Online (Sandbox Code Playgroud)

现在谈到我的问题.当我向user1显示潜在用户的个人资料时,我会考虑所有已经喜欢user1的人(因为我优先考虑这些个人资料):

var likedQuery = Parse.Query.or(new Parse.Query("Match")
    .equalTo("uid1", userId)
    .equalTo("u2action", "L")
    .equalTo("u1action", "E") // user1 has not done anything
    .select("uid2")
    .limit(paginationLimit);
Run Code Online (Sandbox Code Playgroud)

现在这很好,一切都很好.我现在也希望通过每个用户喜欢的数量(流行度)来订购likesQuery.

说这些是喜欢user1的以下用户:

保罗(保罗本人有50个人喜欢他)

洛根(洛根被20人所喜欢)

迈克尔(迈克尔被80人喜欢),

我们想订购所有这些人,以便迈克尔成为第一个用户看到的个人资料.

现在我的问题是,我将如何使用mongoDB?在SQL中这将是非常简单的,只需执行一个表JOIN,使用SUM()和COUNT()按该表排序,并确保您有必要的索引.

在mongoDB中,我看到如何做的唯一方法是uid2likes在每个Match对象上有一个(将被排序)字段,该字段将由cron作业递增,但这是荒谬的并且不能扩展.

我的问题更多的是关于如何以可扩展的方式做到这一点.

use*_*814 3

您可以在 3.4 中使用以下聚合查询。

这里的想法是把$match所有喜欢user1的用户跟在self后面,$lookup得到所有喜欢喜欢user1的用户的用户。

$group并按$sortcount desc 对匹配项进行排序。

$limit限制匹配的用户。

db.colname.aggregate([
  {"$match":{"uid1":userID,"uid2action":"L","uid1action":"E"}},
  {"$lookup":{
    "from":colname,
    "localField":"uid2",
    "foreignField":"uid1",
    "as":"uid2likes"
  }},
  {"$unwind":"$uid2likes"},
  {"$match":{"uid2likes.uid2action":"L"}},
  {"$group":{
    "_id":{"uid1":"$uid1","uid2":"$uid2"},
    "uid2likecount":{"$sum":1}
  }},
  {"$sort":{"uid2likecount":-1}},
  {"$limit":paginationLimit}
])
Run Code Online (Sandbox Code Playgroud)

几个笔记

重要的是使用$lookup + $unwind + $match3.4 中优化的通过将查询谓词移动$match到 内部来运行$lookup。更多的here

您可以利用现有索引(假设您在 uid1 上有一个)来进行初始匹配和查找匹配。

$lookup还可以尝试在 uid2action 上添加索引,看看它是否被+ stage拾取$match。更多herehere

添加索引:

db.colname.createIndex( { uid1: 1 } )
db.colname.createIndex( { uid2action: 1 } )
Run Code Online (Sandbox Code Playgroud)

测量指标用途:

db.colname.aggregate([{$indexStats: {}}, {$project: {key: 0, host: 0}}]).pretty();
Run Code Online (Sandbox Code Playgroud)

解释查询:

db.colname.explain("executionStats").aggregate(above pipeline);
Run Code Online (Sandbox Code Playgroud)

您可以在索引之间交替并检查执行统计信息以查看索引是如何被选取的。也可以尝试复合索引。

使用 3.6,您可以稍微清理一下查询。

db.colname.aggregate([
  {"$match":{"uid1":userID,"uid2action":"L","uid1action":"E"}},
  {"$lookup":{
    "from":colname,
    "let":{"uid2":"$uid2"},
    "pipeline":[
       {"$match":{"$expr":{"$eq":["$uid1","$$uid2"]},"uid2action":"L"}}, 
       {"$count":"count"}
    ],
    "as":"uid2likes"
  }},
  {"$unwind":"$uid2likes"},
  {"$sort":{"uid2likes.count":-1}},
  {"$limit":paginationLimit}
])
Run Code Online (Sandbox Code Playgroud)