Сортировать по совпавшим тегам с помощью SQLAlchemy - PullRequest
0 голосов
/ 19 апреля 2020

У меня есть следующие таблицы. Я хочу осуществлять поиск по тегам и сортировать по сопоставленному количеству тегов.

class DocumentTag(db.Model):
    __tablename__ = "document_tag"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50), nullable=False)
    user_document_id = db.Column(db.Integer, db.ForeignKey("user_document.id"))
    order = db.Column(db.Integer, nullable=False)

    user_document = db.relationship("Document")

class UserDocument(db.Model):
    __tablename__ = "user_document"
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
    document_id = db.Column(db.Integer, db.ForeignKey("document.id"), nullable=False)
    date_added = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
    last_accessed = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
    document_tags = db.relationship(
        "DocumentTag",
        order_by="DocumentTag.order",
        collection_class=ordering_list("order"),
    )
    document = db.relationship("Document")
    document_tag = db.relationship("DocumentTag")

Я пытался искать документы с такими тегами.


tags = ['tag_1', 'tag_2'] # this is tags to search

documents_tags_count = (
    db.session.query(
        UserDocument, func.count(DocumentTag.id).label("num_corres_tags")
    )
    .join(UserDocument, DocumentTag.user_document) # in order to count combination of document_tags and tags
    .filter(
        UserDocument.document_tags.any(DocumentTag.name.in_(tags)),
        UserDocument.user_id == current_user.id,
    )
    .group_by(UserDocument)
    .order_by(desc("num_corres_tags"))
)

Однако метка num_corres_tags показывал не отфильтрованное количество тегов, а все количество тегов, принадлежащих документам. Я хотел получить упорядоченный результат по количеству совпадающих (отфильтрованных) тегов.

Я видел здесь несколько похожих вопросов для MySQL, но не смог найти никакого решения для SQLAlchemy, потому что я действительно новичок в SQL.

Есть какие-нибудь идеи для решения моей проблемы?

1 Ответ

1 голос
/ 19 апреля 2020

Поскольку вы явно присоединяетесь к DocumentTag для подсчета, используйте это объединение и для фильтрации, а не для отдельного выражения подзапроса EXISTS:

documents_tags_count = (
    db.session.query(
        UserDocument, func.count(DocumentTag.id).label("num_corres_tags")
    )
    .join(UserDocument, DocumentTag.user_document) # in order to count combination of document_tags and tags
    .filter(
        DocumentTag.name.in_(tags),
        UserDocument.user_id == current_user.id,
    )
    .group_by(UserDocument)
    .order_by(desc("num_corres_tags"))
)

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

...