ActiveRecord присоединяется к условию удовлетворения всех отношений

mysql ruby-on-rails ruby activerecord rails-activerecord

151 просмотра

2 ответа

542 Репутация автора

У меня есть модель базы данных, как это:

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просто пример идентификатора пользователя.

Проблема в том, что этот запрос, похоже, выбирает всех, у 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);
Автор: Ybrin Источник Размещён: 17.07.2016 11:39

Ответы (2)


8 плюса

1445 Репутация автора

Решение

Так что, если вам не нужно игнорировать сообщения, созданные пользователем, это должно быть что-то вроде этого

Выясните, за какие посты голосовал пользователь, а не за.

Post.where.not(id: Vote.where(user_id: user_id).select(:post_id))
Автор: lusketeer Размещён: 09.08.2016 09:56

1 плюс

555 Репутация автора

Я создал пример, подобный тому, что вы описали. Я создал одного пользователя с идентификатором «1» и пять сообщений с идентификаторами «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}>]
Автор: Tony Размещён: 13.08.2016 01:50
Вопросы из категории :
32x32