gpt4 book ai didi

arrays - MongoDB 数组查询性能

转载 作者:可可西里 更新时间:2023-11-01 09:56:24 26 4
gpt4 key购买 nike

我正在尝试弄清楚什么是适用于约会网站(如应用程序)的最佳架构。用户有一个列表(可能很多),他们可以查看其他用户列表来“喜欢”和“不喜欢”他们。

目前我只是将其他人的列表 ID 存储在 likedBydislikedBy 数组中。当用户“喜欢”一个列表时,它会将他们的列表 ID 放入“喜欢”的列表数组中。但是我现在想跟踪用户喜欢列表的时间戳。这将用于用户的“历史列表”或数据分析。

我需要做两个单独的查询:

查找该用户之前不喜欢或不喜欢的所有事件列表

以及用户“喜欢”/“不喜欢”选择的历史

按时间顺序查找用户 X 喜欢的所有列表

我当前的架构是:

listings
_id: 'sdf3f'
likedBy: ['12ac', 'as3vd', 'sadf3']
dislikedBy: ['asdf', 'sdsdf', 'asdfas']
active: bool

我可以做这样的事情吗?

listings
_id: 'sdf3f'
likedBy: [{'12ac', date: Date}, {'ds3d', date: Date}]
dislikedBy: [{'s12ac', date: Date}, {'6fs3d', date: Date}]
active: bool

我也在考虑为 choices 制作一个新的集合。

choices
Id
userId // id of current user making the choice
userlistId // listing of the user making the choice
listingChoseId // the listing they chose yes/no
type
date

我不确定在执行查找该用户之前不喜欢或不喜欢的所有事件列表时在另一个集合中进行这些选择对性能的影响。

任何见解将不胜感激!

最佳答案

嗯,您显然认为将这些嵌入“列表”文档中是个好主意,这样您对此处介绍的案例的其他使用模式就可以正常工作。考虑到这一点,就没有理由将其丢弃。

不过要澄清一下,您似乎想要的结构是这样的:

{
"_id": "sdf3f",
"likedBy": [
{ "userId": "12ac", "date": ISODate("2014-04-09T07:30:47.091Z") },
{ "userId": "as3vd", "date": ISODate("2014-04-09T07:30:47.091Z") },
{ "userId": "sadf3", "date": ISODate("2014-04-09T07:30:47.091Z") }
],
"dislikedBy": [
{ "userId": "asdf", "date": ISODate("2014-04-09T07:30:47.091Z") },
{ "userId": "sdsdf", "date": ISODate("2014-04-09T07:30:47.091Z") },
{ "userId": "asdfas", "date": ISODate("2014-04-09T07:30:47.091Z") }
],
"active": true
}

这一切都很好,只是有一个问题。因为您在两个数组字段中有此内容,所以您将无法在这两个字段上创建索引。这是一个限制,复合索引中只能包含一种数组类型的字段(或多键)。

因此,为了解决您的第一个查询不能使用索引的明显问题,您可以改用如下结构:

{
"_id": "sdf3f",
"votes": [
{
"userId": "12ac",
"type": "like",
"date": ISODate("2014-04-09T07:30:47.091Z")
},
{
"userId": "as3vd",
"type": "like",
"date": ISODate("2014-04-09T07:30:47.091Z")
},
{
"userId": "sadf3",
"type": "like",
"date": ISODate("2014-04-09T07:30:47.091Z")
},
{
"userId": "asdf",
"type": "dislike",
"date": ISODate("2014-04-09T07:30:47.091Z")
},
{
"userId": "sdsdf",
"type": "dislike",
"date": ISODate("2014-04-09T07:30:47.091Z")
},
{
"userId": "asdfas",
"type": "dislike",
"date": ISODate("2014-04-09T07:30:47.091Z")
}
],
"active": true
}

这允许索引覆盖这种形式:

db.post.ensureIndex({
"active": 1,
"votes.userId": 1,
"votes.date": 1,
"votes.type": 1
})

实际上,您可能需要一些索引来适应您的使用模式,但关键是现在可以拥有您可以使用的索引。

涵盖第一种情况,您有这种形式的查询:

db.post.find({ "active": true, "votes.userId": { "$ne": "12ac" } })

考虑到您显然不会为每个用户同时提供喜欢和不喜欢的选项,这是有道理的。按照该索引的顺序,至少可以使用 active 进行过滤,因为您的否定条件需要扫描其他所有内容。任何结构都无法解决这个问题。

对于另一种情况,您可能希望 userId 位于日期之前的索引中并作为第一个元素。那么你的查询就很简单了:

db.post.find({ "votes.userId": "12ac" })
.sort({ "votes.userId": 1, "votes.date": 1 })

但您可能想知道,以前获取“喜欢”和“不喜欢”的计数就像测试数组的大小一样简单,但现在有点不一样了。不是聚合无法解决的问题:

db.post.aggregate([
{ "$unwind": "$votes" },
{ "$group": {
"_id": {
"_id": "$_id",
"active": "$active"
},
"likes": { "$sum": { "$cond": [
{ "$eq": [ "$votes.type", "like" ] },
1,
0
]}},
"dislikes": { "$sum": { "$cond": [
{ "$eq": [ "$votes.type", "dislike" ] },
1,
0
]}}
])

因此,无论您的实际使用形式如何,您都可以存储文档的任何重要部分以保留在分组 _id 中,然后以简单的方式评估“喜欢”和“不喜欢”的数量。

您可能也不知道将条目从喜欢更改为不喜欢也可以在单个原子更新中完成。

您可以做更多的事情,但出于给定的原因,我更喜欢这种结构。

关于arrays - MongoDB 数组查询性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22947857/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com