Есть ли лучший способ выполнить $ lookup (т.е. СОЕДИНЕНИЕ) с классами набора запросов PyMODM, чем это?

#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, но все же я чувствую, что должен быть лучший способ, чем этот.