我有兩個類:Question和User。 Question類有一個類型的字段,其類型爲Column(ARRAY(Integer))
,而User類有一個對象preferences
,該對象的字段名爲ignored_categories
,也是Column(ARRAY(Integer))
類型。Sqlalchemy:使用兩個ARRAY類型列的過濾操作
我想查詢所有沒有在出現在ignored_categories
字段從用戶的喜好或者以前是真的category_ids
場至少一個值的問題,必須在category_ids
領域的任何其他值不在用戶的偏好字段ignore_categories
中。因此,下面列出的是真實的:
category_ids
= []和ignored_categories
= [1,2,3] =>應該通過。category_ids
= [1,2,4]和ignored_categories
= [1,2,3] =>應該通過。category_ids
= [1]和ignored_categories
= [1,2,3] =>應該忽略。category_ids
= [1,2,3]和ignored_categories
= [1,2,3] =>應該忽略。category_ids
= [1,2,3,4]和ignored_categories
= [1,2,3] =>應該通過。category_ids
= [5,7]和ignored_categories
= [1,2,3] =>應該通過。
這是我想出了這麼遠:
user = DBSession.query(User).filter_by(id=user_id).one() # this gets the user object
query = DBSession.query(Question).order_by(Question.created_at.desc())
query = query.filter(
or_(
not_(
Question.category_ids.overlap(user.preferences.ignored_categories)
),
Question.category_ids.contains(user.preferences.ignored_categories)
)
)
這樣做的問題是,contains
只有測試,如果category_ids
是ignored_categories
一個超集,這不能給出數據的正確結果集,如:
category_ids
= [1]和ignored_categories
= [1,2,3] =>應忽略。
因此,它需要另一個條件來測試是否至少有一個值匹配,而其他條件不匹配。
的overlap
功能僅當存在於兩個陣列的至少一個值的測試,但是此操作失敗測試,如:
category_ids
= [1,2,4]和ignored_categories
= [1,2 ,3] =>應該通過。
哪個應該通過,但它沒有,因爲我需要否定操作。如果我不否定它,它只會過濾沒有任何共同點的數組。
編輯:這是我的表看起來像:
class User(Base, DictSerializable):
__tablename__ = 'users'
__table_args__ = dict(schema='user')
id = Column(types.Id, primary_key=True)
# other fields
class UserPreferences(Base, DictSerializable):
__tablename__ = 'user_preferences'
__table_args__ = dict(schema='user')
id = Column(types.Id, primary_key=True)
user_id = Column(types.Id, ForeignKey(User.id))
ignored_categories = Column(types.ARRAY(types.Number), default=[])
# other fields
user = relationship("User",
backref=backref("preferences", single_parent=True, cascade="all, delete-orphan",
passive_deletes=True, uselist=False),
)
class Question(Base, DictSerializable):
__tablename__ = 'questions'
__table_args__ = dict(schema='question')
id = Column(types.Id, primary_key=True)
user_id = Column(types.Id, ForeignKey(User.id, ondelete="CASCADE", onupdate="CASCADE"))
# other fields
category_ids = Column(types.ARRAY(types.Integer))
user = relationship("User", foreign_keys=user_id,
backref=backref("questions", order_by=id, single_parent=True, uselist=True,
cascade="all, delete-orphan", passive_deletes=True)
)
question_categories = Table('question_categories', Base.metadata,
Column('question_id', types.Integer, ForeignKey(Question.id)),
Column('category_id', types.Integer, ForeignKey(Category.id)))
Question.categories = relationship(Category, secondary=question_categories, backref=backref('questions'))
你需要的是設置的差異操作。您不能模擬交集(「重疊」)和子集(「包含」)的集合差異。你如何完成設置差異取決於你的數據庫。出於這個原因,數組通常被認爲比連接表更不靈活。 – univerio
@univerio我已經更新了表結構的問題。你能以他們的方式推薦我嗎?我應該通過加入聯盟來實現這一點? –
「連接表」我的意思是'CREATE TABLE question_categories(question_id int,category_id int,PRIMARY KEY(question_id,category_id)'。對於您的具體情況,您可能可以使用'ignored_categories.contains(category_ids)',accounting對於'category_ids'爲空的情況。 – univerio