Thanks! That worked beautifully. :) On Mar 19, 11:18 am, Conor <conor.edward.da...@gmail.com> wrote: > Stodge wrote: > > Thanks. That doesn't quite work. Based on my data, the following > > should (and does) work because it only returns document id=1, which > > only has these two tags: > > > tag_list = ['my document', 'source code'] > > session.query(Document).\ > > filter(Document.tags.any(Tag.tag.in_([t for t in tag_list]))).\ > > filter(~Document.tags.any(~Tag.tag.in_([t for t in tag_list]))) > > > The following should return no records, as there is no document that > > has only these tags. Instead it returns document id=2, which only has > > the tag 'random stuff': > > > tag_list = ['my document', 'source code', 'random stuff'] > > session.query(Document).\ > > filter(Document.tags.any(Tag.tag.in_([t for t in tag_list]))).\ > > filter(~Document.tags.any(~Tag.tag.in_([t for t in tag_list]))) > > Try this query instead: > > tag_list = ['my document', 'source code', 'random stuff'] > q = session.query(Document) > for t in tag_list: > q = q.filter(Document.tags.any(Tag.tag == t)) > q = q.filter(~Document.tags.any(~Tag.tag.in_(tag_list))) > > Alternatively, if your database supports aggregating row sets into > arrays/strings (e.g. PostgreSQL supports ARRAY(SELECT ...) to collect > row sets into an array, MySQL and others have GROUP_CONCAT() that I > believe you can use for this purpose), you may prefer a different > technique. I will show an example with PostgreSQL and ARRAY(). > > subq = session.query(Tag.tag) > subq = subq.join(document_tags) > subq = subq.filter(document_tags.c.document_id == Document.id) > subq = subq.order_by(Tag.tag.asc()) > subq = subq.correlate(Document) > subq = subq.subquery() > > q = session.query(Document) > q = q.filter(func.array(subq) == sorted(tag_list)) > q = q.correlate(s) # May not be needed > > This should generate SQL like: > > SELECT <Document columns> > FROM document > WHERE ARRAY( > SELECT tag.tag > FROM tag > JOIN document_tags ON document_tags.tag_id = tag.id > WHERE document_tags.document_id = document.id > ORDER BY tag.tag ASC > ) = %(array_1)s > > where array_1 would be ['my document', 'random stuff', 'source code']. > Note how both the subquery and array_1 have to be sorted. I tend to > prefer this type of query since its complexity doesn't grow as you add > more tags in your search criteria. > > -Conor > > > > > On Mar 19, 10:15 am, Michael Bayer <mike...@zzzcomputing.com> wrote: > > >> select document.* from document join tags on document.id=tags.document_id > >> where tags.tag='foo' and tags.tag='bar' and tags.tag=.... > > >> am I missing something ? that would return no rows in most cases. > > >> if you want to find documents that have an exact list of tags, you'd have > >> to do something like the IN query we started with, and additionally ensure > >> no extra tags remain. > > >> like: > > >> sess.query(Document).\ > >> filter(Document.tags.any(Tag.id.in_([t.id for t in > >> tag_list])).\ > >> filter(~Document.tags.any(~Tag.id.in_([t.id for t in > >> tag_list])) > > >> On Mar 19, 2010, at 8:31 AM, Stodge wrote: > > >>> Now we're getting somewhere: > > >>> expressions = [] > >>> for tag in tag_list: > >>> expressions += [Tag.tag==tag] > >>> documents = > >>> session.query(Document).join(Document.tags).filter(and_(*expressions)) > > >>> Thanks to a Storm example I found. :) > > >>> On Mar 19, 8:12 am, Stodge <sto...@gmail.com> wrote: > > >>>> Ok so far I have this: > > >>>> expressions = [] > >>>> for tag in tag_list: > >>>> expressions += session.query(Document).filter(Tag.tag==tag) > >>>> documents = > >>>> session.query(Document).join(Document.tags).filter(and_(*expressions)) > > >>>> Doesn't work but it's progress! :) > > >>>> On Mar 18, 2:37 pm, Stodge <sto...@gmail.com> wrote: > > >>>>> Thanks that worked beautifully. > > >>>>> On a similar note, how would I match documents with only the tags that > >>>>> I specify in the list? My naive attempt is: > > >>>>> for tag in tag_list: > >>>>> session.query(Document).join(Document.tags).filter_by(tag=tag) > > >>>>> But that doesn't work. > > >>>>> On Mar 15, 10:54 am, "Michael Bayer" <mike...@zzzcomputing.com> wrote: > > >>>>>> Stodgewrote: > > >>>>>>> I have two classes with a third table: > > >>>>>>> document_tags = Table('document_tags', metadata, > >>>>>>> Column('document_id', Integer, ForeignKey('documents.id')), > >>>>>>> Column('tag_id', Integer, ForeignKey('tags.id')) > >>>>>>> ) > > >>>>>>> class Document(Base): > >>>>>>> __tablename__ = 'documents' > > >>>>>>> id = Column(Integer, primary_key=True) > >>>>>>> title = Column(String) > >>>>>>> filename = Column(String) > >>>>>>> tags = relation('Tag', secondary=document_tags, backref='tags') > > >>>>>>> def __init__(self, title, filename): > >>>>>>> self.title = title > >>>>>>> self.filename = filename > > >>>>>>> class Tag(Base): > >>>>>>> __tablename__ = 'tags' > > >>>>>>> id = Column(Integer, primary_key=True) > >>>>>>> tag = Column(String) > > >>>>>>> def __init__(self, tag): > >>>>>>> self.tag = tag > > >>>>>>> I want to find all documents with tags in a given list of tags: > > >>>>>>> documents = > >>>>>>> session.query(Document).filter(Document.tags.in_(tag_list)) > > >>>>>>> except I get the familiar message that the "in_()" operator is not > >>>>>>> currently implemented for many-to-one-relations. > > >>>>>>> I've searched and found some alternatives but I can't get any to work. > >>>>>>> Is there an easy example that will make this work? Thanks > > >>>>>> if the error message says "many-to-one" then that's a bug. Your > >>>>>> relation > >>>>>> is many-to-many. > > >>>>>> in this case the syntactically easiest method is to use any(). > >>>>>> Document.tags.any(Tag.id.in_([t.id for t in tag_list])). > > >>>>>> A join could be more performant, which would be: > > >>>>>> query.join(Document.tags).filter(Tag.id.in_([t.id for t in tag_list])) > >
-- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalch...@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.