Parse.com LEFT JOIN替代方案

时间:2015-04-18 11:25:48

标签: javascript parse-platform nosql

有人可以解释一下像arseSQL这样的noSQL环境中的正确数据结构,以便在SQL中执行等效的LEFT JOIN。我来自一个关系世界,所以我非常乐观地认为我的桌子需要完全重新设计。

我想存储“工作”和“用户”,用户可以在其中发布工作和应用到工作。所以我创建了三个表:“Job”,“User”和“Application”。应用程序有三列:“指向作业的指针”,“指向用户的指针”和“应用程序状态”。

问题是:

  1. 我不能在单个查询中获取用户发布的所有作业,每个作业的应用程序数量。
  2. 我无法在单个查询中获取用户的所有可用作业,也知道该用户是否已应用

    我正在使用parse.com进行此项目。

  3. 编辑赏金

    我有多个解决方案,可以在Job表中使用多个查询或使用数组。每个都有局限性,但我希望了解是否有更好的数据结构或查询来获取这些作业的所有作业。

2 个答案:

答案 0 :(得分:2)

这是可行的。如果您允许少量查询而不是只有一个查询,则有些事情更容易实现。但是我认为如果你允许对结果进行一点内存操作,你可以用一个查询来完成你的特定问题。

// 1. assume that Job contains a pointer to the user who posted it (postingUser)
// 2. assume that Application's user column means the user who applied
// 3. Assume Javascript, though the sdk contains functional equivalents for several languages

var user = // a given user
var jobQuery = new Parse.Query("Job");
jobQuery.equalTo("postingUser", user);
// if you wanted all the jobs posted by user, we'd be ready to go
// but you also want application counts, which forces us to be more roundabout...
var appQuery = new Parse.Query("Application");
appQuery.matchesQuery("job", jobQuery);  // this is the nearest idea to LEFT JOIN
appQuery.include("job");  // eagerly fetch the related job

appQuery.find().then(function(applications) {
    // applications are applications for jobs posted by user
    // so here's the little in-memory work to get jobs (using underscorejs)
    var jobs = [];
    var appCounts = {};
    _.each(applications, function(app) {
        var job = app.get("job");  // remember job was eagerly fetched
        jobs.push(job);
        appCounts[job] = (appCounts[job])? appCounts[job]+1 : 1;

        // Taking your second question to mean "is the user who
        // posted the job also one of its applicants?"
        job["posterIsApplicant"] = app.get("user").id == user.id;
    });
});

完成上述操作后,jobs将包含user发布的作业,appCounts[job]将是任何作业的应用数量,job["posterIsApplicant"]仅为真如果该职位的申请人之一也是发布该职位的用户。

答案 1 :(得分:1)

第二个答案简要说明:严格考虑问题约束(给定数据模型,一个查询,给定输出),我认为问题是过度约束的。我们可以通过放松固定数据模型或单个查询来实现功能目标。

首先,放宽单一查询。我上面的答案我假设了以下数据模型......

Application --1 User (applicant)
          |
          --1 Job --1 User (postingUser)

...并建议应用程序的单个查询,其中应用程序作业通过第二个隐式内部查询与作业匹配。这个想法解决了大部分问题,但错过了没有应用程序的工作(INNER JOIN,正如你所指出的那样)。

修复该错误,我们可以通过以下两个显式查询来实现目标:

var user = // a given user
var jobQuery = new Parse.Query("Job");
jobQuery.equalTo("postingUser", user);
var jobs = [];
jobQuery.find().then(function(results) {
    // requirement 1: jobs posted by a user
    jobs = results;
    var appQuery = new Parse.Query("Application");
    appQuery.containedIn("job", jobs);
    return appQuery.find();
}).then(function(apps) {
    _.each(jobs, function(job) {
        // requirement 1.1: jobs' related to apps (trivial to count them)
        job["applications"] = _.find(apps, function(app) {
            return app.get("job").id == job.id;
        });

        // requirement 2: decorate jobs where the postingUser is an applicant
        // could have combined loops above, but looping again for clarity
        _.each(jobs, function(job) {
            var posterIsApplicant = _.find(apps, function(app) {
                return app.get("applicant").id == user.id
            });
            job["posterIsApplicant"] = app.get("user").id == user.id;
        });            
    });
});

或者,不受数据模型的限制,但只需一个查询,我们就可以通过这种方式排列数据来获得功能结果:

Job --1 User (postingUser)
   |
   --< Application (applications) --1 User (postingUser)

在这里,Job有一个指向用户的指针和一个指针数组(或者如果你希望基数高的关系......我的经验法则是> 100)到Application。如果在其他地方需要,应用程序可以继续有一个指向Job的指针(这可以在beforeSave云代码中维护)。

有了它,它可以通过单个查询实现简单的功能:

var user = // a given user
var jobQuery = new Parse.Query("Job");
jobQuery.equalTo("postingUser", user);
jobQuery.include("applications")l
jobQuery.find().then(function(results) {
    // requirement 1: results contains jobs, each has an array
    // of applications
    // requirement 2: is copy-paste from above
    _.each(results, function(job) {
        var apps = job.get("applications");
        var posterIsApplicant = _.find(apps, function(app) {
            return app.get("applicant").id == user.id
        });
        job["posterIsApplicant"] = app.get("user").id == user.id;
    });            
});