0
class Account has_many :metadata class Keys has_many :metadata class Metadatum belongs_to :key belongs_ to :account 

In Metadatum object I keep additional information about Account, for exapmle 'age'.

In Key object I keep information about type of Metadatum.

Metadatum table:

  • id
  • key_id
  • account_id
  • value

Key table:

  • name
  • data_type

I want to search accounts by multiple metadata. For example

  • Metadatum with value = '18' that belongs to Key with name = 'age'
  • Metadatum with value = 'John' that belongs to Key with name = 'first_name'

My query is:

 accounts.joins(metadata: :key).where("keys.name = ? AND metadata.value = ?", params[:key], params[:value]).where("keys.name = ? AND metadata.value = ?", params[:key1], params[:value1]) 

It is wrong because in my opinion it looks for an Account that has Metadatum with both key_ids and values. No such Metadatum exists - each has only one key_id and value.

What would be the right query?

2 Answers 2

1

If you want accounts that comply with both conditions, I would try:

first = Account.joins(metadata: :key).where("keys.name = ? AND metadata.value = ?", params[:key], params[:value]) final = first.joins(metadata : :key).where("keys.name = ? AND metadata.value = ?", params[:key1], params[:value1]) 

New try (really ugly :))

first_ids = Account.joins(metadata: :key).where("keys.name = ? AND metadata.value = ?", params[:key], params[:value]).pluck(“accounts.id”) final = Account.where(id: first_ids).joins(metadata : :key).where("keys.name = ? AND metadata.value = ?", params[:key1], params[:value1]) 
Sign up to request clarification or add additional context in comments.

3 Comments

Below is the sql query that I have. Still does not show me accounts that has both metadata
SELECT "accounts".* FROM "accounts" INNER JOIN "metadata" ON "metadata"."account_id" = "accounts"."id" AND "metadata"."deleted_at" IS NULL INNER JOIN "keys" ON "keys"."id" = "metadata"."key_id" AND "keys"."deleted_at" IS NULL WHERE "accounts"."deleted_at" IS NULL AND (keys.name = 'first_name' AND metadata.value = 'Robert') AND (keys.name = 'age' AND metadata.value = '18')
I tried a second approach. I don't like it, but it might work.
0

Try following

accounts.joins(metadata: :key) .where("(keys.name = ? AND metadata.value = ?) OR (keys.name = ? AND metadata.value = ?)", params[:key], params[:value], params[:key1], params[:value1]) 

3 Comments

Thanks but this is not what I want, because If I search for "John"(metadata1) that is "18"(metadata2) years old I will also receive all NOT"Johns" that are "18" and all "Johns" that are NOT"18"
Nope in that case your query should be only accounts.joins(metadata: :key).where("(keys.name = ? AND metadata.value = ?)", params[:key], params[:value])
You have to generate dynamic queries depending on the parameters

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.