避免无界数组
通过将数组存储为字段值,您可以嵌入数据并确保将一起访问的数据存储在一起。 但是,如果不限制大量中元素的数量,您的文档可能会超过 16 MB BSON文档大小限制。 无界大量可能会给应用程序资源造成压力,并降低索引性能。
无需嵌入整个数据集,而是使用子集设置和对绑定数组的引用,这可以提高性能并保持文档大小易于管理。 对数据进行子集化时,只需选择要处理的数据的必要部分,这样就可以只关注相关数据,从而减少内存使用量和处理时间。 引用数据时,您链接到外部数据源,而不是直接将其嵌入到文档中。 此方法可提高性能并减小文档大小。 通过使用子集设置和引用,可以绑定数组并更有效地管理日期。
例子
考虑以下用于跟踪书店应用程序的书评的模式。 初始模式对 reviews
字段使用一个大量。
{ title: "Harry Potter", author: "J.K. Rowling", publisher: "Scholastic", reviews: [ { user: "Alice", review: "Great book!", rating: 5 }, { user: "Bob", review: "Didn't like it!", rating: 1 }, { user: "Charlie", review: "Not bad, but could be better.", rating: 3 } ] }
在此模式中, reviews
字段是一个无界大量。 每次为这本书创建新查看时,应用程序都会向reviews
大量添加一个新的子文档。 随着评论数量的增加,该大量可能会变得过大,导致应用程序资源紧张。
在此示例中,书店应用程序只需为每本书显示三个书评。 为避免使用无界数组,可以使用子集设计模式或文档引用,具体取决于您的使用案例。
子集模式
当您需要快速访问权限不经常更新的数据时,对数据进行子集化是最好的选择。 使用 子集模式,您可以在图书文档中嵌入三条评论,以便在单个操作中返回所有必需的信息。 其他评论存储在单独的reviews
集合中。 此模式设计模式具有以下优点:
消除无界大量
控制文档大小
避免使用多个查询
books
集合:
db.books.insertOne( [ { title: "Harry Potter", author: "J.K. Rowling", publisher: "Scholastic", reviews: [ { reviewer: "Alice", review: "Great book!", rating: 5 }, { reviewer: "Charlie", review: "Didn't like it.", rating: 1 }, { reviewer: "Bob", review: "Not bad, but could be better.", rating: 3 } ], } ] )
reviews
集合:
db.reviews.insertMany( [ { reviewer: "Jason", review: "Did not enjoy!", rating: 1 }, { reviewer: "Pam", review: "Favorite book!", rating: 5 }, { reviewer: "Bob", review: "Not bad, but could be better.", rating: 3 } ] )
这种方法会复制数据,导致更新成本高昂。 如果评价不经常更新,则此方法是最佳选择。
参考数据
当您需要管理大型或频繁更新的数据集而不增加文档大小时,引用数据是最佳选择。
要引用数据,存储评论存储在单独的集合中,并向reviews
集合中的文档添加review_id
字段。 使用review_id
字段引用books
集合中的评论。
这种方法解决了无界大量的问题,但会引入延迟,因为您需要查询reviews
集合以检索books
集合的查看信息。 根据您的使用案例,这种额外的延迟可能是可以接受的,以避免无界数组引起的问题。
books
集合:
db.books.insertMany( [ { title: "Harry Potter", author: "J.K. Rowling", publisher: "Scholastic", reviews: ["review1", "review2", "review3"] }, { title: "Pride and Prejudice", author: "Jane Austen", publisher: "Penguin", reviews: ["review4", "review5"] } ] )
reviews
集合:
db.reviews.insertMany( [ { review_id: "review1", reviewer: "Jason", review: "Did not enjoy!", rating: 1 }, { review_id: "review2", reviewer: "Pam", review: "Favorite book!", rating: 5 }, { review_id: "review3", reviewer: "Bob", review: "Not bad, but could be better.", rating: 3 }, { review_id: "review4", reviewer: "Tina", review: "Amazing!", rating: 5 }, { review_id: "review5", reviewer: "Jacob", review: "A little overrated", rating: 4, } ] )
使用 $lookup 联接数组字段
如果您的books
和reviews
信息存储在单独的集合中,则应用程序需要执行$lookup
操作来联接数据。
以下聚合操作连接上一示例中的books
和reviews
集合。
db.books.aggregate( [ { $lookup: { from: "reviews", localField: "reviews", foreignField: "review_id", as: "reviewDetails" } } ] )
该操作返回以下内容:
[ { _id: ObjectId('665de81eeda086b5e22dbcc9'), title: 'Harry Potter', author: 'J.K. Rowling', publisher: 'Scholastic', reviews: [ 'review1', 'review2', 'review3' ], reviewDetails: [ { _id: ObjectId('665de82beda086b5e22dbccb'), review_id: 'review1', reviewer: 'Jason', review: 'Did not enjoy!', rating: 1 }, { _id: ObjectId('665de82beda086b5e22dbccc'), review_id: 'review2', reviewer: 'Pam', review: 'Favorite book!', rating: 5 }, { _id: ObjectId('665de82beda086b5e22dbccd'), review_id: 'review3', reviewer: 'Bob', review: 'Not bad, but could be better.', rating: 3 } ] }, { _id: ObjectId('665de81eeda086b5e22dbcca'), title: 'Pride and Prejudice', author: 'Jane Austen', publisher: 'Penguin', reviews: [ 'review4', 'review5' ], reviewDetails: [ { _id: ObjectId('665de82beda086b5e22dbcce'), review_id: 'review4', reviewer: 'Tina', review: 'Amazing!', rating: 5 }, { _id: ObjectId('665de82beda086b5e22dbccf'), review_id: 'review5', reviewer: 'Jacob', review: 'A little overrated', rating: 4 } ] } ]
在此示例中, $lookup
操作使用图书文档中的reviews
大量和评论文档中的review_id
字段将books
集合与reviews
集合连接起来。 reviewDetails
文档存储组合后的数据。