无法使用 DocumentClient - Nodejs 将项目写入 DynamoDB table
Unable to write item(s) to DynamoDB table utilizing DocumentClient - Nodejs
我对 DynamoDb 绝对是全新的,我正在尝试简单地从 NodeJS Lambda 编写一个对象。根据我阅读和研究的内容,我可能应该使用 aws-sdk
中的 DocumentClient
。我还在此处发现了以下 question 与 DocumentClient 相关的问题,但它似乎并没有解决我的具体问题....不幸的是我真的无法 find/pinpoint。我已经设置了一个调试器来帮助 SAM 本地开发,但它似乎只提供 一些 的错误。
此处显示了代码的实现。
var params = {
TableName: "March-Madness-Teams",
Item: {
"Id": {"S": randstring.generate(9)},
"School":{"S": team_name},
"Seed": {"S": seed},
"ESPN_Id": {"S": espn_id}
}
}
console.log(JSON.stringify(params))
dynamodb.put(params, (error,data) => {
if (error) {
console.log("Error ", error)
} else {
console.log("Success! ", data)
}
})
基本上,我正在使用 cheerio 库和从 DOM 中挑选值来清理网站,并将它们保存到如下所示的 json 对象中。
{
"TableName": "March-Madness-Teams",
"Item": {
"Id": {
"S": "ED311Oi3N"
},
"School": {
"S": "BAYLOR"
},
"Seed": {
"S": "1"
},
"ESPN_Id": {
"S": "239"
}
}
}
当我尝试将此 json 对象推送到 Dynamo 时,出现错误
Error MultipleValidationErrors: There were 2 validation errors:
* MissingRequiredParameter: Missing required key 'TableName' in params
* MissingRequiredParameter: Missing required key 'Item' in params
上面的错误都很好....我认为它不喜欢我将它们包装到字符串中的键的事实,所以我删除了引号并发送了以下内容
{
TableName: "March-Madness-Teams",
Item: {
"Id": {
"S": "ED311Oi3N"
},
"School": {
"S": "BAYLOR"
},
"Seed": {
"S": "1"
},
"ESPN_Id": {
"S": "239"
}
}
}
但是,当我这样做时...我什么也得不到。
这是一个更大的代码片段。
return new Promise((resolve,reject) => {
axios.get('http://www.espn.com/mens-college-basketball/bracketology')
.then(html => {
const dynamodb = new aws.DynamoDB.DocumentClient()
let $ = cheerio.load(html.data)
$('.region').each(async function(index, element){
var preregion = $(element).children('h3,b').text()
var region = preregion.substr(0, preregion.indexOf('(') - 1)
$(element).find('a').each(async function(index2, element2){
var seed = $(element2).siblings('span.rank').text()
if (seed.length > 2){
seed = $(element2).siblings('span.rank').text().substring(0, 2)
}
var espn_id = $(element2).attr('href').split('/').slice(-2)[0]
var team_name = $(element2).text()
var params = {
TableName: "March-Madness-Teams",
Item: {
"Id": randstring.generate(9),
"School":team_name,
"Seed": seed,
"ESPN_Id": espn_id
}
}
console.log(JSON.stringify(params))
// dynamodb.put(params)
// .then(function(data) {
// console.log(`Success`, data)
// })
})
})
})
})
你可以不用类型试试吗?
而不是
"School":{"S": team_name},
例如,使用
"School": team_name,
从你的代码中,我可以看到对 dynamodb 请求的错误承诺。尝试更改您的台词:
dynamodb.put(params).then(function(data) {
console.log(`Success`, data)
})
成为:
dynamodb.put(params).promise().then(function(data) {
console.log(`Success`, data)
})
你也可以结合 await :
await dynamodb.put(params).promise().then(function(data) {
console.log(`Success`, data)
})
exports.lambdaHandler = async (event, context) => {
const html = await axios.get('http://www.espn.com/mens-college-basketball/bracketology')
let $ = cheerio.load(html.data)
const schools = buildCompleteSchoolObject(html, $)
try {
await writeSchoolsToDynamo(schools)
return { statusCode: 200 }
} catch (error) {
return { statusCode: 400, message: error.message }
}
}
const writeSchoolsToDynamo = async (schools) => {
const promises = schools.map(async school => {
await dynamodb.put(school).promise()
})
await Promise.all(promises)
}
const buildCompleteSchoolObject = (html, $) => {
const schools = []
$('.region').each(loopThroughSubRegions(schools, $))
return schools
}
const loopThroughSubRegions = (schools, $) => {
return (index, element) => {
var preregion = $(element).children('h3,b').text()
var region = preregion.substr(0, preregion.indexOf('(') - 1)
$(element).find('a').each(populateSchoolObjects(schools, $))
}
}
const populateSchoolObjects = (schools, $) => {
return (index, element) => {
var seed = $(element).siblings('span.rank').text()
if (seed.length > 2) {
seed = $(element).siblings('span.rank').text().substring(0, 2)
}
var espn_id = $(element).attr('href').split('/').slice(-2)[0]
var team_name = $(element).text()
schools.push({
TableName: "March-Madness-Teams",
Item: {
"Id": randstring.generate(9),
"School": team_name,
"Seed": seed,
"ESPN_Id": espn_id
}
})
}
}
我知道这与我开始时的做法截然不同,但我做了更多的挖掘工作,并为此做了一些工作...我不确定这是否是最好的方法,但我似乎明白了它可以正常工作...让我知道是否需要更改!
哦,我明白你想要什么了。
也许您可以看到上面的代码有效,但是您必须在此处改进一个关于异步的概念 - await 和 promise,尤其是在 lambda 函数上。
我从你上面的代码中得到了一些注释,也许你可以考虑改进你的 lambda :
对 lambda 中的每个 promise 使用 await 并不是最好的方法,因为我们知道 lambda 的时间限制。但有时我们可以在其他情况下这样做。
也许您可以将 dynamodb.put 方法更改为 dynamodb.batchWriteItem :
The BatchWriteItem operation puts or deletes multiple items in one or more tables.
- 或者如果您必须改用 dynamodb.put,请尝试将代码改进为如下所示:
const writeSchoolsToDynamo = async (schools) => {
const promises = schools.map(school => {
dynamodb.put(school).promise()
})
return Promise.all(promises)
}
我对 DynamoDb 绝对是全新的,我正在尝试简单地从 NodeJS Lambda 编写一个对象。根据我阅读和研究的内容,我可能应该使用 aws-sdk
中的 DocumentClient
。我还在此处发现了以下 question 与 DocumentClient 相关的问题,但它似乎并没有解决我的具体问题....不幸的是我真的无法 find/pinpoint。我已经设置了一个调试器来帮助 SAM 本地开发,但它似乎只提供 一些 的错误。
此处显示了代码的实现。
var params = {
TableName: "March-Madness-Teams",
Item: {
"Id": {"S": randstring.generate(9)},
"School":{"S": team_name},
"Seed": {"S": seed},
"ESPN_Id": {"S": espn_id}
}
}
console.log(JSON.stringify(params))
dynamodb.put(params, (error,data) => {
if (error) {
console.log("Error ", error)
} else {
console.log("Success! ", data)
}
})
基本上,我正在使用 cheerio 库和从 DOM 中挑选值来清理网站,并将它们保存到如下所示的 json 对象中。
{
"TableName": "March-Madness-Teams",
"Item": {
"Id": {
"S": "ED311Oi3N"
},
"School": {
"S": "BAYLOR"
},
"Seed": {
"S": "1"
},
"ESPN_Id": {
"S": "239"
}
}
}
当我尝试将此 json 对象推送到 Dynamo 时,出现错误
Error MultipleValidationErrors: There were 2 validation errors:
* MissingRequiredParameter: Missing required key 'TableName' in params
* MissingRequiredParameter: Missing required key 'Item' in params
上面的错误都很好....我认为它不喜欢我将它们包装到字符串中的键的事实,所以我删除了引号并发送了以下内容
{
TableName: "March-Madness-Teams",
Item: {
"Id": {
"S": "ED311Oi3N"
},
"School": {
"S": "BAYLOR"
},
"Seed": {
"S": "1"
},
"ESPN_Id": {
"S": "239"
}
}
}
但是,当我这样做时...我什么也得不到。
这是一个更大的代码片段。
return new Promise((resolve,reject) => {
axios.get('http://www.espn.com/mens-college-basketball/bracketology')
.then(html => {
const dynamodb = new aws.DynamoDB.DocumentClient()
let $ = cheerio.load(html.data)
$('.region').each(async function(index, element){
var preregion = $(element).children('h3,b').text()
var region = preregion.substr(0, preregion.indexOf('(') - 1)
$(element).find('a').each(async function(index2, element2){
var seed = $(element2).siblings('span.rank').text()
if (seed.length > 2){
seed = $(element2).siblings('span.rank').text().substring(0, 2)
}
var espn_id = $(element2).attr('href').split('/').slice(-2)[0]
var team_name = $(element2).text()
var params = {
TableName: "March-Madness-Teams",
Item: {
"Id": randstring.generate(9),
"School":team_name,
"Seed": seed,
"ESPN_Id": espn_id
}
}
console.log(JSON.stringify(params))
// dynamodb.put(params)
// .then(function(data) {
// console.log(`Success`, data)
// })
})
})
})
})
你可以不用类型试试吗?
而不是
"School":{"S": team_name},
例如,使用
"School": team_name,
从你的代码中,我可以看到对 dynamodb 请求的错误承诺。尝试更改您的台词:
dynamodb.put(params).then(function(data) {
console.log(`Success`, data)
})
成为:
dynamodb.put(params).promise().then(function(data) {
console.log(`Success`, data)
})
你也可以结合 await :
await dynamodb.put(params).promise().then(function(data) {
console.log(`Success`, data)
})
exports.lambdaHandler = async (event, context) => {
const html = await axios.get('http://www.espn.com/mens-college-basketball/bracketology')
let $ = cheerio.load(html.data)
const schools = buildCompleteSchoolObject(html, $)
try {
await writeSchoolsToDynamo(schools)
return { statusCode: 200 }
} catch (error) {
return { statusCode: 400, message: error.message }
}
}
const writeSchoolsToDynamo = async (schools) => {
const promises = schools.map(async school => {
await dynamodb.put(school).promise()
})
await Promise.all(promises)
}
const buildCompleteSchoolObject = (html, $) => {
const schools = []
$('.region').each(loopThroughSubRegions(schools, $))
return schools
}
const loopThroughSubRegions = (schools, $) => {
return (index, element) => {
var preregion = $(element).children('h3,b').text()
var region = preregion.substr(0, preregion.indexOf('(') - 1)
$(element).find('a').each(populateSchoolObjects(schools, $))
}
}
const populateSchoolObjects = (schools, $) => {
return (index, element) => {
var seed = $(element).siblings('span.rank').text()
if (seed.length > 2) {
seed = $(element).siblings('span.rank').text().substring(0, 2)
}
var espn_id = $(element).attr('href').split('/').slice(-2)[0]
var team_name = $(element).text()
schools.push({
TableName: "March-Madness-Teams",
Item: {
"Id": randstring.generate(9),
"School": team_name,
"Seed": seed,
"ESPN_Id": espn_id
}
})
}
}
我知道这与我开始时的做法截然不同,但我做了更多的挖掘工作,并为此做了一些工作...我不确定这是否是最好的方法,但我似乎明白了它可以正常工作...让我知道是否需要更改!
哦,我明白你想要什么了。
也许您可以看到上面的代码有效,但是您必须在此处改进一个关于异步的概念 - await 和 promise,尤其是在 lambda 函数上。
我从你上面的代码中得到了一些注释,也许你可以考虑改进你的 lambda :
对 lambda 中的每个 promise 使用 await 并不是最好的方法,因为我们知道 lambda 的时间限制。但有时我们可以在其他情况下这样做。
也许您可以将 dynamodb.put 方法更改为 dynamodb.batchWriteItem :
The BatchWriteItem operation puts or deletes multiple items in one or more tables.
- 或者如果您必须改用 dynamodb.put,请尝试将代码改进为如下所示:
const writeSchoolsToDynamo = async (schools) => {
const promises = schools.map(school => {
dynamodb.put(school).promise()
})
return Promise.all(promises)
}