ActiveRecord连接条件满足所有关系

时间:2016-07-17 23:39:21

标签: mysql ruby-on-rails ruby activerecord rails-activerecord

我有这样的数据库模型:

Post
    has_many :votes
    belongs_to :user
User
    has_many :posts
    has_many :votes
Vote
    belongs_to :post
    belongs_to :user

我想要的是查询他尚未投票的特定用户的所有posts

我试过这样:

Post.left_outer_joins(:votes).where.not(votes: { user_id: 1 })

其中1只是一个示例用户ID。

问题是,此查询似乎会抓取所有posts,其user_id不是1,但至少有一次投票。 但由于不止一个用户会投票支持这些帖子,一旦有多个投票,所有用户都会立即收到所有帖子。

我不知道joins是否是正确的方法,但我的查询将是:

  

给我所有帖子,其中没有一个投票的user_id为1

是否可以为他尚未投票的用户提取posts

编辑:

上述三个表的数据库模式:

投票:

CREATE TABLE "votes" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
        "post_id" integer,
        "user_id" integer,
        "created_at" datetime NOT NULL,
        "updated_at" datetime NOT NULL,
        "vote_type" integer DEFAULT 0);
CREATE INDEX "index_votes_on_post_id" ON "votes" ("post_id");
CREATE INDEX "index_votes_on_user_id" ON "votes" ("user_id");

文章:

CREATE TABLE "posts" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
        "photo_gcs_key" varchar, "photo_gcs_bucket" varchar,
        "user_id" integer, "campaign_id" integer,
        "created_at" datetime NOT NULL,
        "updated_at" datetime NOT NULL);
CREATE INDEX "index_images_on_user_id" ON "images" ("user_id");
CREATE INDEX "index_images_on_campaign_id" ON "images" ("campaign_id");

用户:

CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
        "uid" varchar, "display_name" varchar, "email" varchar,
        "photo_url" varchar, "photo_gcs_key" varchar,
        "photo_gcs_bucket" varchar, "user_name" varchar,
        "created_at" datetime NOT NULL,
        "updated_at" datetime NOT NULL);

2 个答案:

答案 0 :(得分:8)

因此,如果你不关心忽略用户创建的帖子,它应该是这样的

找出用户首先投票的帖子,然后是未投票的帖子。

Post.where.not(id: Vote.where(user_id: user_id).select(:post_id))

答案 1 :(得分:1)

我设置了一个像你描述的那样的例子。我创建了一个用户,id' 1'和五个帖子,ID' 1' - ' 5'。然后我创建了喜欢帖子' 2'和' 4'。其他答案中的语法不起作用,它抱怨not。以下作品用于选择用户不喜欢的帖子(1,3,5)' 1'

irb(main):062:0> Post.where(Sequel.~(id: Vote.select(:post_id).where(user_id: 1)))
=> #<Sequel::MySQL::Dataset: "SELECT * FROM `posts` WHERE (`id` NOT IN (SELECT `post_id` FROM `votes` WHERE (`user_id` = 1)))">

irb(main):063:0> Post.where(Sequel.~(id: Vote.select(:post_id).where(user_id: 1))).all
=> [#<Post @values={:id=>1, :photo_gcs_key=>nil, :photo_gcs_bucket=>nil, :user_id=>1, :campaign_id=>nil, :created_at=>2016-08-12 17:23:53 -0700, :updated_at=>2016-08-12 17:23:53 -0700}>, #<Post @values={:id=>3, :photo_gcs_key=>nil, :photo_gcs_bucket=>nil, :user_id=>1, :campaign_id=>nil, :created_at=>2016-08-12 17:23:56 -0700, :updated_at=>2016-08-12 17:23:56 -0700}>, #<Post @values={:id=>5, :photo_gcs_key=>nil, :photo_gcs_bucket=>nil, :user_id=>1, :campaign_id=>nil, :created_at=>2016-08-12 17:23:57 -0700, :updated_at=>2016-08-12 17:23:57 -0700}>]