模型
现在我有两个 PyMODM 模型:
class PlaylistTrack(MongoModel):
post = fields.ReferenceField(Post, primary_key=True)
playlist_position = fields.IntegerField() # Uses zero-indexing
class Post(MongoModel):
reddit_post_id = fields.CharField(required=True, primary_key=True)
subreddit = fields.CharField()
exists_in_playlist = fields.BooleanField()
#
# ... some more irrelevant fields
#
如您所见,PlaylistTrack
模型包含对模型的引用 id Post
。
问题
在我的代码中,我想获取与某些 Post 字段以及 PlaylistTrack 字段匹配的所有 PlaylistTrack,如下所示:
# This is psuedocode, not actually valid PyMODM syntax
tracks = PlaylistTrack.objects.raw(
{"post.subreddit": subreddit_name,
"playlist_position": {"$gt": pos_in_spotify, "$lte": new_pos}}
)
PyMODM 不允许我这样做,因为 post 不是嵌入式文档,但它是另一个帖子的引用字段。在研究文档后,我发现 mongodbaggregate()
管道与$lookup
操作符相结合会做一个左外连接,让我可以做这样的事情:
playlisttracks = PlaylistTrack.objects.all().aggregate(
{
"$lookup": {
"from": "post",
"localField": "_id",
"foreignField": "_id",
"as": "playlisttrack_post"
}
},
{
"$match": {
"playlisttrack_post.subreddit": self.subreddit_name,
"playlisttrack_post.exists_in_playlist": True
}
},
{
"$sort": {"playlist_position": pymongo.ASCENDING}
})
问题在于它返回的是 PyMongo CommandCursor 类型,而不是 PyMODM QuerySet 类型。这意味着我不能使用 QuerySet 类方法(与 PyMODM 模型一起使用更自然),而是必须将所有内容都转换为 PyMongo,这有点违背了使用 PyMODM 的目的和不自然的感觉。
我的解决方法
因此,相反,我将其作为一种 hacky 解决方法
posts = Post.objects.raw({"$and":
[{"subreddit": self.subreddit_name},
{"exists_in_playlist": True}]})
post_ids = [p.reddit_post_id for p in posts]
# Get all tracks in playlist in order
playlisttracks = PlaylistTrack.objects \
.raw({"_id": {"$in": post_ids}}) \
.order_by([("playlist_position", pymongo.ASCENDING)]
我没有与 进行连接$lookup
,而是找到我想要的 Post 并将其用作查询的一部分。
这确保返回的对象是 PyMODM QuerySet 对象。
我的问题
有没有更好的方法来使用本机 PyMODM 语法来解决这个问题?我是否误解了如何使用 PyMongo / PyMODM 的用途?
我知道在 NoSQL 中使用连接有点棘手,但我仍然觉得肯定有比这更好的方法。