【发布时间】:2020-12-01 06:37:16
【问题描述】:
我有一个名为 URLArray 的 DynamoDB 表,其中包含 URL 列表 (myURL) 和唯一视频名称 (myKey)。
我需要做两件事:
- 当用户点击下一个视频按钮时,需要从这个 URLArray 中选择一个随机条目。可能有数万行。
用户已登录应用程序。每次他们看完视频时,都会记录视频的唯一视频名称。所以....当用户观看视频时,会将其添加到用户信息行下名为 Users 的表中的列表中。
- Soo...当用户单击第 1 点中的下一个视频按钮时选择的这个随机条目必须与他们已经看过的视频列表进行比较。确保该特定用户不会再次随机出现。
到目前为止,我做了一些效率极低的事情,虽然可行,但效果并不好:
顺便说一下,我正在使用 AppSync + GraphQL 与 DynamoDB 表进行交互。我首先获得了 URLArray 的本地副本:
//Gets a list of the Key/URL pairs in the UrlArrays table in GraphQL ****IN CONSTRUCTOR, so we have this URLArray data when componentDidMount()****
listUrlArrays = async () => {
try {
URLData = await API.graphql(graphqlOperation(ListUrlArrays)); //GraphQL query
//URLData[] is available in the entire class
this.setState({urlArrayLength: apiData.data.listURLArrays.items.length}); //gets the length of URLArray (i.e. how many videos are in the database)
}
}
作为概述,当用户点击下一个视频时:
//When clicking next video
async nextVideo(){
await this.logVideosSeen(); //add myKey to the list of videos in *Users* table the logged in user has now seen
await this.getURL(); //get the NEXT upcoming video's details, for Video Player to play and make sure it's not been seen before
}
//This will update the 'listOfVideosSeen[]' in Users table with videos unique myKey, the logged in user has seen
logVideosSeen = async () => {
.......
}
async getURL() {
var dbIndex = this.getUniqueRandomNumber(this.state.urlArrayLength); //Choose a number between 0 and N number of videos in URLArray
//the hasVideoBeenSeen() basically gets the list of videos a user has already seen from `Users` table with the GraphQL getusers command, and creates a local copy of this list (can get big). I use javascripts indexOf() to check whether myKey already exists in the list
while(await this.hasVideoBeenSeen(this.state.URLData[dbIndex].myKey)) //while true i.e. user has seen that video before
{
dbIndex = this.getUniqueRandomNumber(this.state.urlArrayLength); //get another random number to fetch a new myKey
}
//If false, we'll exit the loop and know we've got a not seen before myKey, proceed to set to play...
if(dbIndex != null){
this.setState({ playURL: this.state.URLData[dbIndex].vidURL }); //Retrieve the URL from the local URLArray that we're going to play (i.e. the next video to come)
}
}
如果需要,我可以分享更多代码,但基本上我想知道如何:
-
让 Lambda 函数根据当前 URLArray 的大小选择一个随机数(我可能需要保留 URLArray 的本地副本)。但我认为这里的第 2 点确实效率低下..
-
让 Lambda 函数根据用户表检查(while 循环)是否已看到 myKey。主要是将这种计算负担转移到云端,而不是应用运行的本地设备。
三思后......
感谢赛斯的建议。我已经考虑了一段时间,虽然随机性要求仍然适用,但我认为你的建议有些道理。我需要随机性的原因是,例如,2 个用户并排坐着,无法预测接下来会出现哪个视频。它不应该是可预测的视频序列。我不确定是否可以将 Scan 函数与 AWS Amplify/GraphQL 一起使用。所以请记住这里发生了两件事:(1) 视频上传,将其记录在 URLArray 中以供将来参考。 (2) 用户观看之前未看过的随机视频,然后移动到另一个未看过的随机视频
*(1) 我喜欢你使用数字来索引 URLArray 的想法,这有助于让生活更轻松一些。所以第一个 URL 在索引 0 处,下一个在 1 处……
我在这里的想法(为了避免我执行 ListUrlArrays() 并将整个数组本地带到手机),是为 URLArray 表创建一个名为 VideoNumber 的 GSI。这将是具有数字 0-N 的唯一 VideoNumber 列。所以想象上面的图表有另一个名为 VideoNumber 的列。第 1 行的 VideoNumber 设置为 0,第 2 行的 VideoNumber 设置为 1 等等……然后我需要做的就是在设备上本地生成一个介于 0-N 之间的随机数,调用特定于该 GSI 的 getURLArrayIdbyVideoNumber() 查询,使用我们刚刚生成的数字,它将从行中解锁我需要的信息。瞧!我认为现在大部分沉重的负担都转移了。
问题:在每个视频上传之前,如何轻松获取表格中当前的总行数N(或行数)?然后我会加一。
我可以做的另一件事是将此当前计数保存在另一个我用于持久数据的 DynamoDB 表中,在上传之前从那里读取数字,并在上传后写入 N+1 以增加它(每次 2 次 DynamoDB 操作上传)。这并不理想。
*(2)
当用户观看完视频后,我可以登录一个列表(在 DynamoDB 中的用户信息下),他们已经看过哪些视频。因此,例如,这现在可以是一个看过的列表:[3,12,73,108,57] 表示他们迄今为止看过的 5 个视频。当用户单击 nextVideo() 时,我们将生成一个随机的 newNumber,并立即将其与已看到列表中的任何数字进行比较。我使用seenlist.indexOf(newNumber),如果列表中不存在 newNumber,它会再次运行或停止。然后我可以通过 GSI 查询,并从 URLArray 中检索相关信息以显示视频。
我认为这个indexOf() 是设备上最大的计算负担,并且随着seenList 的增加显然会变慢一些。但是使用纯整数应该比我之前使用的字母数字 myKey 更快。欢迎任何其他建议:)
我还没有尝试过,但这只是一个想法,因为我需要保留随机元素。但首先,你知道我如何轻松找到 URLArray 的行数或表数吗?
【问题讨论】:
-
哪个属性是你的分区键(ID 字段?)。你在使用排序键吗?下一个视频真的需要随机播放,还是只是用户从未看过的内容?
-
@chai86 我建议检查这个线程stackoverflow.com/questions/10666364/…
-
@SethGeoghegan 没有排序键。正如您所说,随机洗牌的主要原因是它必须点击用户以前从未见过的条目。我在列表中记录了登录用户已经看到的项目,以进行比较。对于数据库看似简单的事情,我仍然没有找到一个直接的解决方案
标签: react-native amazon-dynamodb dynamodb-queries