MongoDB 如何引用数组?
MongoDB How do I reference an array?
我正在尝试创建一个 MongoDB 数据库,其中包含两个集合:学生和课程。
第一个集合“学生”包含:
from pymongo import MongoClient
import pprint
client = MongoClient("mongodb://127.0.0.1:27017")
db = client.Database
student = [{"_id":"0",
"firstname":"Bert",
"lastname":"Holden"},
{"_id":"1",
"firstname":"Sam",
"lastname":"Olsen"},
{"_id":"2",
"firstname":"James",
"lastname":"Swan"}]
students = db.students
students.insert_many(student)
pprint.pprint(students.find_one())
第二个合集“课程”包含:
from pymongo import MongoClient
import pprint
client = MongoClient("mongodb://127.0.0.1:27017")
db = client.Database
course = [{"_id":"10",
"coursename":"Databases",
"grades":"[{student_id:0, grade:83.442}, {student_id:1, grade:45.323}, {student_id:2, grade:87.435}]"}]
courses = db.courses
courses.insert_many(course)
pprint.pprint(courses.find_one())
然后我想使用聚合来查找学生和相应课程的成绩。
from pymongo import MongoClient
import pprint
client = MongoClient("mongodb://127.0.0.1:27017")
db = client["Database"]
pipeline = [
{
"$lookup": {
"from": "courses",
"localField": "_id",
"foreignField": "student_id",
"as": "student_course"
}
},
{
"$match": {
"_id": "0"
}
}
]
pprint.pprint(list(db.students.aggregate(pipeline)))
我不确定 student_id/grade 是否在“课程”集合中正确实施,所以这可能是我的理由之一 returns [].
如果我为每个学生创建单独的课程,聚合就可以工作,但这似乎是在浪费内存,所以我想要一个包含所有 student_ids 和成绩的课程。
预期输出:
[{'_id': '0',
'firstname': 'Bert',
'lastname': 'Holden',
'student_course': [{'_id': '10',
'coursename': 'Databases',
'grade': '83.442',
'student_id': '0'}]}]
有几点值得一提..
- 文件“courses.py”中的示例代码正在插入成绩作为
表示数组的字符串,而不是实际数组。这是
Matt 在评论中指出,您要求
解释。这是我试图解释的 - 如果你插入一个字符串
它看起来像一个你不能对其执行 $unwind 或 $lookup 的数组
sub-elements 因为它们不是 sub-elements,它们是
字符串.
- 您在保存学生成绩的课程中有数组数据,这些数据是
所需的数据点,但您开始聚合
学生 collection。相反,也许改变你的观点
位并从课程 collections 而不是
学生视角。如果这样做,您可能 re-qualify
要求为 - “显示所有课程和学生成绩
学生编号为 0"。
- 您的数组数据似乎有不匹配的数据类型。学号
是字符串变量“array”中的一个整数,但是学生
collection 将学生 ID 作为字符串。需要保持一致
为 $lookup 正常工作(如果不想执行一堆
铸造)。
但是,尽管如此,这里还是有可能解决您的问题。我修改了 python 代码,包括重新定义聚合...
我的测试数据库的名称是 pythontest
,如本代码示例所示。
此数据库 必须 在 运行 代码之前存在,否则会出错。
文件students.py
from pymongo import MongoClient
import pprint
client = MongoClient("mongodb://127.0.0.1:27017")
db = client.pythontest
student = [{"_id":"0",
"firstname":"Bert",
"lastname":"Holden"},
{"_id":"1",
"firstname":"Sam",
"lastname":"Olsen"},
{"_id":"2",
"firstname":"James",
"lastname":"Swan"}]
students = db.students
students.insert_many(student)
pprint.pprint(students.find_one())
然后是课程文件。注意字段 grades
不再是一个字符串,而是一个有效的数组 object?请注意学生 ID 是一个字符串,而不是一个整数? (实际上,UUID 或 int 等更强大的数据类型可能更可取)。
文件courses.py
from pymongo import MongoClient
import pprint
client = MongoClient("mongodb://127.0.0.1:27017")
db = client.pythontest
course = [{"_id":"10",
"coursename":"Databases",
"grades": [{ "student_id": "0", "grade": 83.442}, {"student_id": "1", "grade": 45.323}, {"student_id": "2", "grade": 87.435}]}]
courses = db.courses
courses.insert_many(course)
pprint.pprint(courses.find_one())
...最后,具有更改的聚合管道的聚合文件...
文件aggregation.py
from pymongo import MongoClient
import pprint
client = MongoClient("mongodb://127.0.0.1:27017")
db = client.pythontest
pipeline = [
{ "$match": { "grades.student_id": "0" } },
{ "$unwind": "$grades" },
{ "$project": { "coursename": 1, "student_id": "$grades.student_id", "grade": "$grades.grade" } },
{
"$lookup":
{
"from": "students",
"localField": "student_id",
"foreignField": "_id",
"as": "student"
}
},
{
"$unwind": "$student"
},
{ "$project": { "student._id": 0 } },
{ "$match": { "student_id": "0" } }
]
pprint.pprint(list(db.courses.aggregate(pipeline)))
运行 程序的输出
> python3 aggregation.py
[{'_id': '10',
'coursename': 'Databases',
'grade': 83.442,
'student': {'firstname': 'Bert', 'lastname': 'Holden'},
'student_id': '0'}]
程序末尾的数据格式可能不尽如人意,但可以通过操作聚合进行调整。
** 编辑 **
因此,如果您想从学生而不是从课程中接近它,您仍然可以执行该聚合,但由于数组在课程中,因此聚合会稍微复杂一些。 $lookup 必须利用管道本身来准备外部数据结构:
学生视角的汇总
db.students.aggregate([
{ $match: { _id: "0" } },
{ $addFields: { "colStudents._id": "$_id" } },
{
$lookup:
{
from: "courses",
let: { varStudentId: "$colStudents._id"},
pipeline:
[
{ $unwind: "$grades" },
{ $match: { $expr: { $eq: ["$grades.student_id", "$$varStudentId" ] } } },
{ $project: { course_id: "$_id", coursename: 1, grade: "$grades.grade", _id: 0} }
],
as: "student_course"
}
},
{ $project: { _id: 0, student_id: "$_id", firstname: 1, lastname: 1, student_course: 1 } }
])
输出
> python3 aggregation.py
[{'firstname': 'Bert',
'lastname': 'Holden',
'student_course': [{'course_id': '10',
'coursename': 'Databases',
'grade': 83.442}],
'student_id': '0'}]
终于可以看一看了..
TLDR; see Mongo Playground
此解决方案要求您将 grades
存储为实际对象而不是字符串。
考虑以下数据库结构:
db={
// Collection
"students": [
{
"_id": "0",
"firstname": "Bert",
"lastname": "Holden"
},
{
"_id": "1",
"firstname": "Sam",
"lastname": "Olsen"
},
{
"_id": "2",
"firstname": "James",
"lastname": "Swan"
}
],
// Collection
"courses": [
{
"_id": "10",
"coursename": "Databases",
"grades": [
{
student_id: "0",
grade: 83.442
},
{
student_id: "1",
grade: 45.325
},
{
student_id: "2",
grade: 87.435
}
]
}
],
}
您可以使用以下查询实现您想要的结果:
db.students.aggregate([
{
$match: {
_id: "0"
}
},
{
$lookup: {
from: "courses",
pipeline: [
{
$unwind: "$grades"
},
{
$match: {
"grades.student_id": "0"
}
},
{
$group: {
"_id": "$_id",
"coursename": {
$first: "$coursename"
},
"grade": {
$first: "$grades.grade"
},
"student_id": {
$first: "$grades.student_id"
}
}
}
],
as: "student_course"
}
}
])
我正在尝试创建一个 MongoDB 数据库,其中包含两个集合:学生和课程。
第一个集合“学生”包含:
from pymongo import MongoClient
import pprint
client = MongoClient("mongodb://127.0.0.1:27017")
db = client.Database
student = [{"_id":"0",
"firstname":"Bert",
"lastname":"Holden"},
{"_id":"1",
"firstname":"Sam",
"lastname":"Olsen"},
{"_id":"2",
"firstname":"James",
"lastname":"Swan"}]
students = db.students
students.insert_many(student)
pprint.pprint(students.find_one())
第二个合集“课程”包含:
from pymongo import MongoClient
import pprint
client = MongoClient("mongodb://127.0.0.1:27017")
db = client.Database
course = [{"_id":"10",
"coursename":"Databases",
"grades":"[{student_id:0, grade:83.442}, {student_id:1, grade:45.323}, {student_id:2, grade:87.435}]"}]
courses = db.courses
courses.insert_many(course)
pprint.pprint(courses.find_one())
然后我想使用聚合来查找学生和相应课程的成绩。
from pymongo import MongoClient
import pprint
client = MongoClient("mongodb://127.0.0.1:27017")
db = client["Database"]
pipeline = [
{
"$lookup": {
"from": "courses",
"localField": "_id",
"foreignField": "student_id",
"as": "student_course"
}
},
{
"$match": {
"_id": "0"
}
}
]
pprint.pprint(list(db.students.aggregate(pipeline)))
我不确定 student_id/grade 是否在“课程”集合中正确实施,所以这可能是我的理由之一 returns [].
如果我为每个学生创建单独的课程,聚合就可以工作,但这似乎是在浪费内存,所以我想要一个包含所有 student_ids 和成绩的课程。
预期输出:
[{'_id': '0',
'firstname': 'Bert',
'lastname': 'Holden',
'student_course': [{'_id': '10',
'coursename': 'Databases',
'grade': '83.442',
'student_id': '0'}]}]
有几点值得一提..
- 文件“courses.py”中的示例代码正在插入成绩作为 表示数组的字符串,而不是实际数组。这是 Matt 在评论中指出,您要求 解释。这是我试图解释的 - 如果你插入一个字符串 它看起来像一个你不能对其执行 $unwind 或 $lookup 的数组 sub-elements 因为它们不是 sub-elements,它们是 字符串.
- 您在保存学生成绩的课程中有数组数据,这些数据是 所需的数据点,但您开始聚合 学生 collection。相反,也许改变你的观点 位并从课程 collections 而不是 学生视角。如果这样做,您可能 re-qualify 要求为 - “显示所有课程和学生成绩 学生编号为 0"。
- 您的数组数据似乎有不匹配的数据类型。学号 是字符串变量“array”中的一个整数,但是学生 collection 将学生 ID 作为字符串。需要保持一致 为 $lookup 正常工作(如果不想执行一堆 铸造)。
但是,尽管如此,这里还是有可能解决您的问题。我修改了 python 代码,包括重新定义聚合...
我的测试数据库的名称是 pythontest
,如本代码示例所示。
此数据库 必须 在 运行 代码之前存在,否则会出错。
文件students.py
from pymongo import MongoClient
import pprint
client = MongoClient("mongodb://127.0.0.1:27017")
db = client.pythontest
student = [{"_id":"0",
"firstname":"Bert",
"lastname":"Holden"},
{"_id":"1",
"firstname":"Sam",
"lastname":"Olsen"},
{"_id":"2",
"firstname":"James",
"lastname":"Swan"}]
students = db.students
students.insert_many(student)
pprint.pprint(students.find_one())
然后是课程文件。注意字段 grades
不再是一个字符串,而是一个有效的数组 object?请注意学生 ID 是一个字符串,而不是一个整数? (实际上,UUID 或 int 等更强大的数据类型可能更可取)。
文件courses.py
from pymongo import MongoClient
import pprint
client = MongoClient("mongodb://127.0.0.1:27017")
db = client.pythontest
course = [{"_id":"10",
"coursename":"Databases",
"grades": [{ "student_id": "0", "grade": 83.442}, {"student_id": "1", "grade": 45.323}, {"student_id": "2", "grade": 87.435}]}]
courses = db.courses
courses.insert_many(course)
pprint.pprint(courses.find_one())
...最后,具有更改的聚合管道的聚合文件...
文件aggregation.py
from pymongo import MongoClient
import pprint
client = MongoClient("mongodb://127.0.0.1:27017")
db = client.pythontest
pipeline = [
{ "$match": { "grades.student_id": "0" } },
{ "$unwind": "$grades" },
{ "$project": { "coursename": 1, "student_id": "$grades.student_id", "grade": "$grades.grade" } },
{
"$lookup":
{
"from": "students",
"localField": "student_id",
"foreignField": "_id",
"as": "student"
}
},
{
"$unwind": "$student"
},
{ "$project": { "student._id": 0 } },
{ "$match": { "student_id": "0" } }
]
pprint.pprint(list(db.courses.aggregate(pipeline)))
运行 程序的输出
> python3 aggregation.py
[{'_id': '10',
'coursename': 'Databases',
'grade': 83.442,
'student': {'firstname': 'Bert', 'lastname': 'Holden'},
'student_id': '0'}]
程序末尾的数据格式可能不尽如人意,但可以通过操作聚合进行调整。
** 编辑 **
因此,如果您想从学生而不是从课程中接近它,您仍然可以执行该聚合,但由于数组在课程中,因此聚合会稍微复杂一些。 $lookup 必须利用管道本身来准备外部数据结构:
学生视角的汇总
db.students.aggregate([
{ $match: { _id: "0" } },
{ $addFields: { "colStudents._id": "$_id" } },
{
$lookup:
{
from: "courses",
let: { varStudentId: "$colStudents._id"},
pipeline:
[
{ $unwind: "$grades" },
{ $match: { $expr: { $eq: ["$grades.student_id", "$$varStudentId" ] } } },
{ $project: { course_id: "$_id", coursename: 1, grade: "$grades.grade", _id: 0} }
],
as: "student_course"
}
},
{ $project: { _id: 0, student_id: "$_id", firstname: 1, lastname: 1, student_course: 1 } }
])
输出
> python3 aggregation.py
[{'firstname': 'Bert',
'lastname': 'Holden',
'student_course': [{'course_id': '10',
'coursename': 'Databases',
'grade': 83.442}],
'student_id': '0'}]
终于可以看一看了..
TLDR; see Mongo Playground
此解决方案要求您将 grades
存储为实际对象而不是字符串。
考虑以下数据库结构:
db={
// Collection
"students": [
{
"_id": "0",
"firstname": "Bert",
"lastname": "Holden"
},
{
"_id": "1",
"firstname": "Sam",
"lastname": "Olsen"
},
{
"_id": "2",
"firstname": "James",
"lastname": "Swan"
}
],
// Collection
"courses": [
{
"_id": "10",
"coursename": "Databases",
"grades": [
{
student_id: "0",
grade: 83.442
},
{
student_id: "1",
grade: 45.325
},
{
student_id: "2",
grade: 87.435
}
]
}
],
}
您可以使用以下查询实现您想要的结果:
db.students.aggregate([
{
$match: {
_id: "0"
}
},
{
$lookup: {
from: "courses",
pipeline: [
{
$unwind: "$grades"
},
{
$match: {
"grades.student_id": "0"
}
},
{
$group: {
"_id": "$_id",
"coursename": {
$first: "$coursename"
},
"grade": {
$first: "$grades.grade"
},
"student_id": {
$first: "$grades.student_id"
}
}
}
],
as: "student_course"
}
}
])