"Inner join" 喜欢 Flask、Jinja 中的 MongoDB
"Inner join" like with MongoDB in Flask, Jinja
我正在尝试使用 Flask 执行 'inner join' like 和两个 MongoDB 集合。
我想我应该使用 $lookup
来实现,我目前的路线是:
@app.route("/perfumes")
def perfumes():
perfumes = mongo.db.perfumes.find()
users = mongo.db.perfumes.aggregate(
[
{
"$lookup": {
"from": "mongo.db.users",
"localField": "author",
"foreignField": "username",
"as": "creator",
}
}
]
)
return render_template("perfumes.html", title="Perfumes", perfumes=perfumes, users=users)
在我的模板中,我正在遍历一个集合中的 perfumes
并希望访问 users
集合中的所有数据,因为每个香水项目都是由一个用户创建的。
perfumes
集合有一个 author
字段,应该用于 link users
集合中的 username
字段。
我的模板的一个非常简化(精简)的版本如下所示:
% for perfume in perfumes %}
{{ perfume.name }}
Created by {{ <HERE I WANT TO HAVE MY ITEM CREATOR> }} on {{ perfume.date_updated.strftime('%d-%m-%Y') }}
{% endfor %}
为了让这个“join”工作并能够访问两个集合中该项目的所有数据,我缺少什么?
谢谢!!
注意:我想访问的不仅仅是创建者的用户名,例如个人资料图片等,这就是我需要加入的原因。
更新:这些是我用于两个数据库的结构:
{
"perfumes": {
"author": "<string>",
"brand": "<string>",
"name": "<string>",
"descritpion": "<text field>",
"date_updated": "<date>",
"public": "<boolean>",
"picture": "<string>"
},
"users": {
"username": "<string>",
"first_name": "<string>",
"last_name": "<string>",
"email": "<string>",
"is_admin": "<boolean>",
"avatar": "<string>"
}
}
因此 perfumes
中的 author
可以 link 与 users
中的 username
一起使用。
您可以创建一个 jinja 过滤器以连接来自两个游标的信息,然后在 jinja 上对其进行迭代,就好像它是一个字典列表一样。
开始创建自定义 jinja 过滤器,其中聚合游标是 mongo.db.perfumes.aggregate
行的输出:例如page_filters.py 文件
from .. import app
@app.template_filter()
def get_user_information(perfume_cursor):
""" Creates a generator to get extra info of user """
# Transform mongo cursor into a list of dicts
perfume_cursor = list(perfume_cursor)
for item in perfume_cursor:
extra_info = mongo.db.users.find_one({"username": item['author']}, {"first_name": 1, "profile_picture": 1})
# Declare below your desired user info
item['user_info'] = dict(first_name=extra_info.first_name,profile_picture=extra_info.profile_picture)
yield item
要使我们的过滤器在模板中可用,我们只需将其导入我们的顶级 init.py
# Make sure app has been initialized first to prevent circular imports.
from .util import page_filters
现在在 jinja 上,只需使用过滤器
{% for perfume in (perfumes | get_user_information) %}
{{ perfume['name'] }}
Created by {{ perfume['user_info']['first_name']}} on {{ perfume['date_updated'].strftime('%d-%m-%Y') }}
{% endfor %}
尽管如此,您应该使查询更具体,只获取必要的用户字段,否则您的记忆中可能有太多信息。我们使用生成器的原因是提供一种处理数据的方法,而无需先将整个数据源加载到内存中。
参考:
https://uniwebsidad.com/libros/explore-flask/chapter-8/custom-filters
https://www.lachlaneagling.com/reducing-memory-consumption-python/
您可以通过简单的聚合来完成。试试下面的代码:
cur = mongo.db.perfumes.aggregate(
[
{
'$lookup': {
'from': 'users', # You can directly specify on which collection you want to lookup
'localField': 'author',
'foreignField': 'username',
'as': 'creator',
}
},
{
'$unwind' : '$creator'
},
{
'$project': {
'username' : '$creator.username',
'perfumeName' : '$name',
'date_updated' : '$date_updated',
'profilePicture' : '$creator.avatar',
..., # Rest of the items that you want to display
'_id': 0
}
}
]
)
Return 结果如下:
return render_template("perfumes.html", title="Perfumes", perfumes=cur) # You don't need to pass users
在模板中显示如下:
{% for perfume in perfumes %}
{{ perfume['perfumeName'] }}
Created by {{ perfume['username'] }} on {{ perfume['date_updated'].strftime('%d-%m-%Y') }}
{% endfor %}
希望对您有所帮助。
我正在尝试使用 Flask 执行 'inner join' like 和两个 MongoDB 集合。
我想我应该使用 $lookup
来实现,我目前的路线是:
@app.route("/perfumes")
def perfumes():
perfumes = mongo.db.perfumes.find()
users = mongo.db.perfumes.aggregate(
[
{
"$lookup": {
"from": "mongo.db.users",
"localField": "author",
"foreignField": "username",
"as": "creator",
}
}
]
)
return render_template("perfumes.html", title="Perfumes", perfumes=perfumes, users=users)
在我的模板中,我正在遍历一个集合中的 perfumes
并希望访问 users
集合中的所有数据,因为每个香水项目都是由一个用户创建的。
perfumes
集合有一个 author
字段,应该用于 link users
集合中的 username
字段。
我的模板的一个非常简化(精简)的版本如下所示:
% for perfume in perfumes %}
{{ perfume.name }}
Created by {{ <HERE I WANT TO HAVE MY ITEM CREATOR> }} on {{ perfume.date_updated.strftime('%d-%m-%Y') }}
{% endfor %}
为了让这个“join”工作并能够访问两个集合中该项目的所有数据,我缺少什么?
谢谢!!
注意:我想访问的不仅仅是创建者的用户名,例如个人资料图片等,这就是我需要加入的原因。
更新:这些是我用于两个数据库的结构:
{
"perfumes": {
"author": "<string>",
"brand": "<string>",
"name": "<string>",
"descritpion": "<text field>",
"date_updated": "<date>",
"public": "<boolean>",
"picture": "<string>"
},
"users": {
"username": "<string>",
"first_name": "<string>",
"last_name": "<string>",
"email": "<string>",
"is_admin": "<boolean>",
"avatar": "<string>"
}
}
因此 perfumes
中的 author
可以 link 与 users
中的 username
一起使用。
您可以创建一个 jinja 过滤器以连接来自两个游标的信息,然后在 jinja 上对其进行迭代,就好像它是一个字典列表一样。
开始创建自定义 jinja 过滤器,其中聚合游标是 mongo.db.perfumes.aggregate
行的输出:例如page_filters.py 文件
from .. import app
@app.template_filter()
def get_user_information(perfume_cursor):
""" Creates a generator to get extra info of user """
# Transform mongo cursor into a list of dicts
perfume_cursor = list(perfume_cursor)
for item in perfume_cursor:
extra_info = mongo.db.users.find_one({"username": item['author']}, {"first_name": 1, "profile_picture": 1})
# Declare below your desired user info
item['user_info'] = dict(first_name=extra_info.first_name,profile_picture=extra_info.profile_picture)
yield item
要使我们的过滤器在模板中可用,我们只需将其导入我们的顶级 init.py
# Make sure app has been initialized first to prevent circular imports.
from .util import page_filters
现在在 jinja 上,只需使用过滤器
{% for perfume in (perfumes | get_user_information) %}
{{ perfume['name'] }}
Created by {{ perfume['user_info']['first_name']}} on {{ perfume['date_updated'].strftime('%d-%m-%Y') }}
{% endfor %}
尽管如此,您应该使查询更具体,只获取必要的用户字段,否则您的记忆中可能有太多信息。我们使用生成器的原因是提供一种处理数据的方法,而无需先将整个数据源加载到内存中。
参考: https://uniwebsidad.com/libros/explore-flask/chapter-8/custom-filters https://www.lachlaneagling.com/reducing-memory-consumption-python/
您可以通过简单的聚合来完成。试试下面的代码:
cur = mongo.db.perfumes.aggregate(
[
{
'$lookup': {
'from': 'users', # You can directly specify on which collection you want to lookup
'localField': 'author',
'foreignField': 'username',
'as': 'creator',
}
},
{
'$unwind' : '$creator'
},
{
'$project': {
'username' : '$creator.username',
'perfumeName' : '$name',
'date_updated' : '$date_updated',
'profilePicture' : '$creator.avatar',
..., # Rest of the items that you want to display
'_id': 0
}
}
]
)
Return 结果如下:
return render_template("perfumes.html", title="Perfumes", perfumes=cur) # You don't need to pass users
在模板中显示如下:
{% for perfume in perfumes %}
{{ perfume['perfumeName'] }}
Created by {{ perfume['username'] }} on {{ perfume['date_updated'].strftime('%d-%m-%Y') }}
{% endfor %}
希望对您有所帮助。