簡體   English   中英

MongoDB 如何引用數組?

[英]MongoDB How do I reference an array?

我正在嘗試創建一個 MongoDB 數據庫,其中包含兩個 collections:學生和課程。

第一個集合“學生”包含:

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 是否正確實現,所以這可能是我的 arregation 返回 [] 的原因之一。

如果我為每個學生創建單獨的課程,則聚合有效,但這似乎浪費了 memory,所以我想要一個包含所有學生 ID 和成績的課程。

預計 output:

 [{'_id': '0',
  'firstname': 'Bert',
  'lastname': 'Holden',
  'student_course': [{'_id': '10',
                      'coursename': 'Databases',
                      'grade': '83.442',
                      'student_id': '0'}]}]

有幾點值得一提。

  1. 您在文件“courses.py”中的示例代碼將成績作為表示數組而不是實際數組的字符串插入。 Matt 在評論中指出了這一點,您要求解釋。 這是我試圖解釋的——如果你插入一個看起來像數組的字符串,你不能對子元素執行 $unwind 或 $lookup,因為它們不是子元素,它們是字符串的一部分。
  2. 您在保存學生成績的課程中有數組數據,這是所需的數據點,但您開始對學生集合進行聚合。 相反,也許稍微改變一下你的觀點,從課程 collections 而不是學生的角度來看。 如果這樣做,您可能會將要求重新限定為 - “向我顯示學生 ID 為 0 的所有課程和學生成績”。
  3. 您的數組數據似乎數據類型不匹配。 學生 ID 是字符串變量“array”中的 integer,但學生集合將學生 ID 作為字符串。 需要保持一致才能使 $lookup 正常工作(如果不想執行大量轉換)。

但是,盡管如此,這里有一個可能解決您的問題的方法。 我已經修改了 python 代碼,包括對聚合的重新定義......

如本代碼示例所示,我的測試數據庫的名稱是pythontest 該數據庫必須在運行代碼之前存在,否則會出錯。

文件學生.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 是一個字符串,而不是 integer? (實際上,UUID 或 int 等更強大的數據類型可能更可取)。

文件課程.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())

...最后,具有更改的聚合管道的聚合文件...

文件聚合.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)))

運行程序Output

> 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 } }
])

Output

> python3 aggregation.py
[{'firstname': 'Bert',
  'lastname': 'Holden',
  'student_course': [{'course_id': '10',
                      'coursename': 'Databases',
                      'grade': 83.442}],
  'student_id': '0'}]

終於可以看這個了。。

TLDR; 見蒙戈游樂場

此解決方案要求您將grades存儲為實際的 object 與字符串。

考慮以下數據庫結構:

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"
    }
  }
])

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM