#python #mongodb #pymongo #pymodm
#python #mongodb #pymongo #pymodm
Вопрос:
Модель
Прямо сейчас у меня есть две модели 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
модель включает идентификатор ссылки на Post
модель.
Проблема
В моем коде я хочу получить все списки воспроизведения, которые соответствуют некоторому полю Post, а также полю 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 не является встроенным документом, но это поле ссылки на другой post. Изучив документацию, я обнаружил, что aggregate()
конвейер mongodb в сочетании с $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}
})
Проблема в том, что это возвращает тип CommandCursor PyMongo, а не тип набора запросов PyMODM. Это означает, что я не могу использовать методы класса QuerySet (которые более естественны для использования с моделями PyMODM), а скорее должен преобразовать все в PyMongo, что похоже на поражение цели использования PyMODM и неестественно.
Мой обходной путь
Поэтому вместо этого я делаю это как хитрый обходной путь
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
, я просто нахожу нужную мне запись и использую ее как часть моего запроса.
Это гарантирует, что возвращаемый объект является объектом набора запросов PyMODM.
Мой вопрос
Есть ли лучший способ сделать это, используя собственный синтаксис PyMODM? Я неправильно понимаю, как использовать PyMongo / PyMODM, поскольку они были предназначены для использования?
Я знаю, что с объединениями довольно сложно работать в NoSQL, но все же я чувствую, что должен быть лучший способ, чем этот.