【问题标题】:Aggregating 3 MongoDB collections - (Python, Flask, Jinja)聚合 3 个 MongoDB 集合 - (Python、Flask、Jinja)
【发布时间】:2020-08-31 06:15:06
【问题描述】:

感谢在这里找到的巨大帮助,我设法为 MongoDB 中的 2 个集合建立了一些聚合。

@app.route("/perfume/<id>", methods=["POST", "GET"])
def perfume(id):
    perfume = mongo.db.perfumes.find_one({"_id": ObjectId(id)})
    form = AddReviewForm()
    cur = mongo.db.perfumes.aggregate(
        [
            {
                "$lookup": {
                    "from": "users",
                    "localField": "author",
                    "foreignField": "username",
                    "as": "creator",
                }
            },
            {"$unwind": "$creator"},
            {
                "$project": {
                    "_id": "$_id",
                    "perfumeName": "$name",
                    "perfumeBrand": "$brand",
                    "perfumeDescription": "$description",
                    "date_updated": "$date_updated",
                    "perfumePicture": "$picture",
                    "isPublic": "$public",
                    "perfumeType": "$perfume_type",
                    "username": "$creator.username",
                    "firstName": "$creator.first_name",
                    "lastName": "$creator.last_name",
                    "profilePicture": "$creator.avatar",
                }
            },
            {"$match": {"_id": ObjectId(id)}},
        ]
    )
    return render_template(
        "perfume.html", title="Perfumes", cursor=cur, perfume=perfume, form=form
    )

我现在想向该聚合中添加第三个集合。

我的目标如下:我现在有 3 个集合,perfumesusersreviews,我想在模板中显示香水(来自香水集合的文档)、来自创建者的数据(用户集合中的文档)和评论中的数据(评论集合中的文档)。

我目前正在设法完成前两个,但我现在正在添加“评论香水”功能。

由于审阅者也是用户,我想将这个新集合聚合到当前查找中。

此集合(评论)只有 3 个字段:_idreview_authorreviewreview_author 必然会出现在用户集合中,因为他们必须登录才能查看。

我还设法将审阅文档的_id(来自reviews 集合)作为数组元素插入perfumes 集合中。 我需要的新聚合 lookup 怎么样才能包含来自所有三个集合的模板数据? 我很乐意阅读帮助!

目前我的架构如下:

{
    "perfumes": {
        "_id": "_id",
        "author": "<string>",  <== used to unwind with following collection
        "brand": "<string>",
        "name": "<string>",
        "perfume_type": "<string>",
        "description": "<text field>",
        "date_updated": "<date>",
        "public": "<boolean>",
        "picture": "<string>",
        "review": "<array>"
    },
    "users": {
        "_id": "_id",
        "username": "<string>",  <== used to unwind to previous coll, needs to link to next
        "first_name": "<string>",
        "last_name": "<string>",
        "email": "<string>",
        "is_admin": "<boolean>",
        "avatar": "<string>"
    },
    "reviews": {
        "_id": "_id",
        "review_author": "<string>", <== to be used as a link
        "review": "<text field>"
    },
}

谢谢!

更新:

这是来自perfumes的示例文档

[
    {
        "_id": {
            "$oid": "5ebd751e0a52cd0dade39491"
        },
        "author": "Guillermo",
        "brand": "A new Brand",
        "name": "A new Perfume",
        "perfume_type": "Oriental",
        "description": "<p>This is the description</p>",
        "date_updated": {
            "$date": "2020-05-14T16:43:10.801Z"
        },
        "public": false,
        "picture": "generic.png",
        "review": [
            {
                "$oid": "5ebd752c0a52cd0dade39492"
            }
        ]
    }
]

这是来自users的示例文档:

[
    {
        "_id": {
            "$oid": "5eb09b0a7b62cdd2e8800d96"
        },
        "username": "Guillermo",
        "first_name": "Guillermo",
        "last_name": "Brachetta",
        "email": "brachetta@me.com",
        "password": "pbkdf2:sha256:150000$4vanQ3Qe$83031f081327e26c1125b861054f1d184bdb4373af323e6a10602587f6d40607",
        "is_admin": true,
        "avatar": "a92de23ae01cdfde.jpg"
    }
]

这是来自reviews的示例文档:

[
    {
        "_id": {
            "$oid": "5ebd752c0a52cd0dade39492"
        },
        "review_author": "Guillermo",
        "review": "<p>This is one review</p>"
    }
]

因此,一位用户可以制作多种香水。一款香水可以有很多评论。 不同的用户可以为相同或不同的香水创建评论。

更新 2:

这看起来很有希望,我对此感到非常兴奋! 我将在模板中简要说明我的目标:

{% for item in cursor &}
  <perfume name>
  <perfume brand>
  <perfume description>
  <perfume picture>
  <author username (of the perfume)>
  <author first and last names>
  <date created>
  <eventually other information>
{% if current_user == author %}
  <button edit>
  <button delete>
{% endif %}
  <button review <=+ available to all logged in users>
{% endfor %}

{% for item in cursor['review'] <= this is not working %}
  <perfume review>
  <perfume review author>
  <perfume review author avatar>
  <eventually other information>
{% endfor %}

通过双重聚合,我实现了所有这一切,但显然是对评论的循环。 展望未来,我相信这会有所进展! :) P.S.:这只是一个非常示意性的概念!

【问题讨论】:

  • 您能否提供一些来自每个相关集合的示例文档?
  • 完成,期待!!谢谢!
  • 我认为users 集合中的username 应该是“Guillermo”。 review_author 可以不是香水的创造者吗?
  • 是的,我拿错了用户。我现在更新了。对此我很抱歉。
  • 是的,任何用户都可以评论香水,不一定是作者。香水可以有很多评论(来自一个或不同的用户)。

标签: python mongodb pymongo


【解决方案1】:

试试下面的代码:

cur = db.perfumes.aggregate([
    {
        '$lookup': {
            'from': 'users',
            'localField': 'author',
            'foreignField': 'username',
            'as': 'creator'
        }
    },
    {
        '$unwind': '$creator'
    },
    {
        '$unwind': {
            'path': '$review',
            'preserveNullAndEmptyArrays': True
        }
    },
    {
        '$lookup': {
            'from': 'review',
            'let': {'rid': {'$toString': '$review._id'}},
            'pipeline': [{
                '$match': {
                    '$expr': {
                        '$eq': ['$$rid', {'$toString': '$_id'}]
                    }
                }
            }],
            'as': 'userReviews'
        }
    },
    {
        '$unwind': '$userReviews'
    },
    {
        '$lookup': {
            'from': 'users',
            'localField': 'userReviews.review_author',
            'foreignField': 'username',
            'as': 'reviewUserInfo'
        }
    },
    {
        '$unwind': '$reviewUserInfo'
    },
    {
        '$group': {
            '_id':'$_id',
            'perfumeName': {'$first': '$name'},
            'perfumeBrand': {'$first': '$brand'},
            'perfumeDescription': {'$first': '$description'},
            'date_updated': {'$first': '$date_updated'},
            'perfumePicture': {'$first': '$picture'},
            'isPublic': {'$first': '$public'},
            'perfumeType': {'$first': '$perfume_type'},
            'username': {'$first': '$creator.username'},
            'firstName': {'$first': '$creator.first_name'},
            'lastName': {'$first': '$creator.last_name'},
            'profilePicture': {'$first': '$creator.avatar'},
            'userReviews': {
                '$push': {
                    'reviewId': '$userReviews._id',
                    'review_author': '$userReviews.review_author',
                    'review': '$userReviews.review',
                    'review_author_first_name': '$reviewUserInfo.first_name',
                    'review_author_last_name': '$reviewUserInfo.last_name',
                    'review_author_email': '$reviewUserInfo.email',
                    'review_author_avatar': '$reviewUserInfo.avatar'
                }
            }
        }
    },
])

输出:

{
    "_id" : ObjectId("5ebd7eec93256dc00c8f6f6c"),
    "perfumeName" : "A new Perfume",
    "perfumeBrand" : "A new Brand",
    "perfumeDescription" : "<p>This is the description</p>",
    "date_updated" : {
            "$date" : "2020-05-14T16:43:10.801Z"
    },
    "perfumePicture" : "generic.png",
    "isPublic" : false,
    "perfumeType" : "Oriental",
    "username" : "Guillermo",
    "firstName" : "Guillermo",
    "lastName" : "Brachetta",
    "profilePicture" : null,
    "userReviews" : [
        {
            "reviewId" : ObjectId("5ebd752c0a52cd0dade39492"),
            "review_author" : "Guillermo",
            "review" : "<p>This is one review</p>",
            "review_author_first_name" : "Guillermo",
            "review_author_last_name" : "Brachetta",
            "review_author_email" : "brachetta@me.com",
            "review_author_avatar" : "a92de23ae01cdfde.jpg"
        }
    ]
}

P.S. - 您可以使用$match 运算符来匹配特定用户,就像您在 OP 中所做的那样,您可以使用 $project 运算符来投影更多字段并获得所需的输出。

【讨论】:

  • 哇,我永远不会想出这么复杂的东西!惊人的!让我看看如何实现这一点,因为它不是开箱即用的。使用它“按原样”循环光标,我得到的香水作者与评论一样多。也许我没有很好地使用我的模板?或者我需要调整光标?我刚刚更新了问题,希望我更清楚。太棒了,非常感谢!我希望你能帮我做最后的润色!!
  • 或者我只是想念如何匹配香水的创造者?我一头雾水,哈哈!
  • 如果您认为这样可以更轻松,我也可以将我的路线和模板发送给您?
  • 嘿,伙计,冷静,我们在这里为您提供帮助。昨天,我的睡眠时间表落后了,所以我无法调查。但是,我总是很乐意提供帮助。 :)
猜你喜欢
  • 2018-03-06
  • 1970-01-01
  • 2020-08-25
  • 1970-01-01
  • 2014-05-27
  • 2013-06-17
  • 2017-07-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多