Pregunta

Sólo para actualizar esto, ya que parece que mucha gente llegar a esto, si usted está utilizando los carriles 4 vistazo a las respuestas de Trung Lê` y VinniVidiVicci.

Topic.where.not(forum_id:@forums.map(&:id))

Topic.where(published:true).where.not(forum_id:@forums.map(&:id))

Estoy esperando que hay una solución fácil que no implique find_by_sql, si no, entonces supongo que tendrá que trabajar.

encontré este artículo que hace referencia a esto:

Topic.find(:all, :conditions => { :forum_id => @forums.map(&:id) })

que es el mismo que

SELECT * FROM topics WHERE forum_id IN (<@forum ids>)

Me pregunto si hay una manera de hacerlo NOT IN con eso, como:

SELECT * FROM topics WHERE forum_id NOT IN (<@forum ids>)
¿Fue útil?

Solución

Estoy usando esto:

Topic.where('id NOT IN (?)', Array.wrap(actions))

Donde actions es una matriz con: [1,2,3,4,5]

Editar:

para los carriles 4 notación:

Article.where.not(title: ['Rails 3', 'Rails 5']) 

Otros consejos

Para su información, en los largueros 4, puede utilizar la sintaxis not:

Article.where.not(title: ['Rails 3', 'Rails 5'])

Se puede intentar algo como:

Topic.find(:all, :conditions => ['forum_id not in (?)', @forums.map(&:id)])

Es posible que tenga que hacer @forums.map(&:id).join(','). No puedo recordar si Rails el argumento en una lista CSV si es enumerable.

También puede hacer esto:

# in topic.rb
named_scope :not_in_forums, lambda { |forums| { :conditions => ['forum_id not in (?)', forums.select(&:id).join(',')] }

# in your controller 
Topic.not_in_forums(@forums)

El uso de Arel:

topics=Topic.arel_table
Topic.where(topics[:forum_id].not_in(@forum_ids))

o, si se prefiere:

topics=Topic.arel_table
Topic.where(topics[:forum_id].in(@forum_ids).not)

y desde los carriles 4 sobre: ??

topics=Topic.arel_table
Topic.where.not(topics[:forum_id].in(@forum_ids))

Tenga en cuenta que el tiempo que no quiere que el forum_ids a ser la lista de los identificadores, sino más bien una sub consulta, si es así, usted debe hacer algo como esto antes de recibir los mensajes:

@forum_ids = Forum.where(/*whatever conditions are desirable*/).select(:id)

De esta manera se obtiene todo en una sola consulta: algo como:

select * from topic 
where forum_id in (select id 
                   from forum 
                   where /*whatever conditions are desirable*/)

Observe también que con el tiempo usted no quiere hacer esto, sino más bien una unión -. Lo que podría ser más eficiente

Para ampliar sobre la respuesta @Trung Lê, en los carriles 4, puede hacer lo siguiente:

Topic.where.not(forum_id:@forums.map(&:id))

Y se podría dar un paso más allá. Si necesita primer filtro para Temas única publicados y después filtran los identificadores que no desea, usted puede hacer esto:

Topic.where(published:true).where.not(forum_id:@forums.map(&:id))

Rieles 4 hace que sea mucho más fácil!

La solución aceptada falla si @forums está vacía. Para solucionar esto lo tenía que hacer

Topic.find(:all, :conditions => ['forum_id not in (?)', (@forums.empty? ? '' : @forums.map(&:id))])

O, si utiliza los carriles 3 +:

Topic.where( 'forum_id not in (?)', (@forums.empty? ? '' : @forums.map(&:id)) ).all

La mayoría de las respuestas anteriores que debería ser suficiente, pero si usted está haciendo mucho más de tales predicados y combinaciones complejas echa un vistazo a squeel. Usted será capaz de hacer algo como:

Topic.where{{forum_id.not_in => @forums.map(&:id)}}
Topic.where{forum_id.not_in @forums.map(&:id)} 
Topic.where{forum_id << @forums.map(&:id)}

Es posible que desee echar un vistazo a la meta_where complemento Ernie Miller. La instrucción SQL:

SELECT * FROM topics WHERE forum_id NOT IN (<@forum ids>)

... podría expresarse así:

Topic.where(:forum_id.nin => @forum_ids)

Ryan Bates de Railscasts creado una buen screencast explicar MetaWhere .

No estoy seguro si esto es lo que estás buscando, pero a mis ojos sin duda se ve mejor que una consulta SQL incrustado.

El post original menciona específicamente el uso de identificadores numéricos, pero vine aquí en busca de la sintaxis para hacer un NO IN con una matriz de cadenas.

ActiveRecord se encargará de que muy bien para usted también:

Thing.where(['state NOT IN (?)', %w{state1 state2}])

¿Pueden estos identificadores de foro ser resuelto de una manera pragmática? p.ej. Puede encontrar estos foros de alguna manera - si ese es el caso, usted debe hacer algo como

Topic.all(:joins => "left join forums on (forums.id = topics.forum_id and some_condition)", :conditions => "forums.id is null")

Lo que sería más eficiente que hacer un SQL not in

De esta manera optimiza para facilitar su lectura, pero no es tan eficiente en términos de consultas de bases de datos:

# Retrieve all topics, then use array subtraction to
# find the ones not in our list
Topic.all - @forums.map(&:id)

Se puede utilizar SQL en sus condiciones:

Topic.find(:all, :conditions => [ "forum_id NOT IN (?)", @forums.map(&:id)])

Piggybacking fuera de jonnii:

Topic.find(:all, :conditions => ['forum_id not in (?)', @forums.pluck(:id)])

usando desplume en lugar de mapeo sobre los elementos

RailsConf 2012 10 cosas que usted no sabía carriles podrían hacer

Cuando se consulta una matriz en blanco escribe "<< 0" a la matriz, donde en el bloque para que no vuelva "NULO" y romper la consulta.

Topic.where('id not in (?)',actions << 0)

Si las acciones podrían ser una matriz vacía o en blanco.

Aquí está una más compleja "no en" consulta utilizando una subconsulta en los carriles 4 utilizando squeel. Por supuesto, muy lento en comparación con el equivalente SQL, pero bueno, funciona.

    scope :translations_not_in_english, ->(calmapp_version_id, language_iso_code){
      join_to_cavs_tls_arr(calmapp_version_id).
      joins_to_tl_arr.
      where{ tl1.iso_code == 'en' }.
      where{ cavtl1.calmapp_version_id == my{calmapp_version_id}}.
      where{ dot_key_code << (Translation.
        join_to_cavs_tls_arr(calmapp_version_id).
        joins_to_tl_arr.    
        where{ tl1.iso_code == my{language_iso_code} }.
        select{ "dot_key_code" }.all)}
    }

Los 2 primeros métodos en el ámbito de aplicación son otros ámbitos que declaran los alias cavtl1 y TL1. << es el no en el operador en squeel.

Espero que esto ayude a alguien.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top