I am currently working on an AWS project, the following issue came up:
export async function main(event, context, callback) {
const params = {
FilterExpression: 'parent_id = :parent_id',
TableName: 'product',
ExpressionAttributeValues: {
':parent_id': event.queryStringParameters.parent_id
},
};
try {
const result = await dynamoDbLib.call("scan", params);
callback(null, success(result.Items));
} catch (e) {
callback(null, failure({ status: false }));
}
This all works fine. But I want to be able to NOT give an expressionattribute, so that it returns ALL of my objects instead of just the ones with the matching parent_id.
Any help is much appreciated!
Thank you in advance,
Bram
You are using a FilterExpression, thus you have to provide ExpressionAttributeValues for the filter expression. You simply need to remove the FilterExpression and ExpressionAttributeValues parameters if you want the Scan operation to return all table items.
Related
I'm attempting to set up my DynamoDB table so I can query the data via a rest API. My table has a partition key (id) which is a randomly generated ID, a sort key (name) and a List of strings (domain).
I have also set up a global secondary index for the "name" field.
I'm attempting to write a lambda that will search for items using both the name and possible search the domain array also. Is this possible? If so how do I set up the table as I'm currently getting this error:
Query key condition not supported
Here is my Lambda query code:
async function query(tableName, searchTerm) {
return new Promise((resolve, reject) => {
const params = {
IndexName: "nameIndex",
ExpressionAttributeNames: {
"#name": "name",
},
ExpressionAttributeValues: {
":topic": { S: searchTerm },
},
KeyConditionExpression: "begins_with(#name, :topic)",
TableName: tableName,
};
ddb.query(params, (err, data) => {
if (err) {
reject(err);
} else {
console.log("Success", data.Items);
resolve(data.Items);
}
});
});
}
A PK must be provided as a value. You can't do expressions like begins with on a PK.
Here are a lot of example programs doing queries with Node:
https://github.com/aws-samples/aws-dynamodb-examples/tree/master/DynamoDB-SDK-Examples/node.js/WorkingWithQueries
I currently have the following code in a codebase using "#apollo/client": "^3.4.17",
const getFrontEndApiSchema = async (authToken: string, hostname: string) => {
const executor = async ({
document,
variables,
}: Parameters<Parameters<typeof introspectSchema>[0]>[0]) => {
const fetchResult = await crossFetch(`${resolveApiUri(hostname)}/graphql`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authentication-Token': authToken,
},
body: JSON.stringify({ query: print(document), variables }),
})
return fetchResult.json()
}
return makeExecutableSchema({
typeDefs: wrapSchema({
schema: buildClientSchema(await unzipSchema()),
executor,
}),
})
}
export const getSchema = async () => {
const frontEndSchema = await getFrontEndApiSchema()
return stitchSchemas({
subschemas: frontEndSchema ? [frontEndSchema, schema] : [schema],
mergeDirectives: true,
})
}
const apolloClient = createApolloClient(
{
schema,
rootValue: { request: req },
},
getAuthenticationToken(req),
false,
)
Which works and fires off requests. However we noticed during a Telemetry exercise (whereby we are trying to track traces through individual operations in DataDog / NewRelic) that a single operation is effectively being split up into it's constituent queries and sent without it's parent operation name.
It's not so clear to me from reading the docs why I would need to this executor function for graphql queries rather than the standard Apollo link chain (similar to what i'm using for the client side apollo client).
So I removed the unneeded executor function to the following.
makeExecutableSchema({
typeDefs: wrapSchema({
schema: buildClientSchema(await unzipSchema()),
}),
})
This worked in so far as the operations where being made and return a result, however ostensibly it was returning results which matched those which would be returned if unauthenticated, (i.e. no authentication token set in the header).
I've checked my error link and have logged context headers and it appears to have the token.
I've also tried swapping the Schemalink for a normal link with no success.
export default function createApolloClient(
schema: SchemaLink.Options,
token: string,
isTest?: boolean,
) {
const link = from([
authLink(token),
serverErrorLink(),
...(__DEV__ ? [logLink(true)] : []),
new SchemaLink(schema),
])
return new ApolloClient({
link,
cache: createCache(),
ssrMode: true,
queryDeduplication: true,
...(!isTest && {
defaultOptions: {
watchQuery: {
fetchPolicy: 'cache-and-network',
},
query: { fetchPolicy: 'cache-first' },
},
}),
})
}
A typical graphql operation I'm sending
query myOperationName{
user {
id
firstName
}
query2{
id
}
query3{
id
}
}
When I do print(document) in the body of my original executor function I am getting
query2{
id
}
etc
So my question is how server side do I construct the correct Apollo client/ link chain combo such that operations are not stripped of their operation names? And any additional clarity on whether it's necessary to use the SchemaLink at all if my express server is on a different box to the api it talks to would be helpful
I want to make a query to return all entries with a certain userID, in this case Will666. I have a primaryKey and a sortKey.
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB({region: 'eu-west-2', apiVersion: '2012-08-10'});
exports.handler = (event, context, callback) => {
const params = {
TableName: "signalepisodes",
KeyConditionExpression: "userID = :a",
ExpressionAttributeValues: {
":a": "Will666"
}
};
dynamodb.query(params, function(err, data){
if (err) {
console.log(err);
callback(err);
} else {
console.log(data);
const items = data.Items.map(
(dataField) => {
return { userID: dataField.userID.S, uploadDate: dataField.uploadDate.N, epTitle: dataField.epTitle.S };
}
);
callback(null, items);
}
});
};
i get this error message when i test it. I guess my syntax is wrong but i can't work it out.
"errorType": "MultipleValidationErrors",
my dynamoDB table looks like this:
The DynamoDB SDK has two types of client:
low-level client: new AWS.DynamoDB(...)
high-level client: new AWS.DynamoDB.DocumentClient(...)
You are currently using #1, but you are supplying attributes to your query as if you were using the document client #2.
So, either switch to the DocumentClient, and continue to use:
{":a": "Will666"}
Or stick with the low-level client and change your attributes to indicate value types, for example:
{":a": {"S": "Will666"}}
I'd recommend the DocumentClient because it significantly simplifies the marshalling and unmarshalling of data.
I would also recommend updating your code from the old callback style asynchronous code to the newer Promise-based options. For example, something like this:
exports.handler = async (event, context) => {
const params = {
TableName: "signalepisodes",
KeyConditionExpression: "userID = :a",
ExpressionAttributeValues: { ":a": "Will666" }
};
const items = await dynamodb.query(params).promise();
for (const item of items) {
console.log('Item:', item);
}
return items;
}
I am quite new on DynamoDB, I just create a table where I inserted some dummy rows just to test the read / write functions.
Here is my data.
I create a Lambda to access these data, via Partition Key ok Sort Key but I ended up with a null return every time :'(
Here is the code of my lambda :
const dynamodb = new AWS.DynamoDB.DocumentClient({apiVersion: '2012-08-10', region: 'eu-west-1'});
exports.handler = async (event,context,callback) => {
var params = {
TableName : "DontMissAPlaceTable",
KeyConditionExpression: "Partition_Key = :id",
ExpressionAttributeValues: {
":id": {"S" : "media_001"}
}
};
dynamodb.query(params, function(err, data) {
if (err) {
console.log(err, err.stack);
callback(null, {
statusCode: '500',
body: err
});
} else {
console.log(data)
callback(null, {
statusCode: '200',
body: data
});
}
})
};
I first thought it was lack of access to the table but it seems I have the right permissions.
I am quite sure it's a dummy problem but i can't figure it out ...
Thanks for help :D
Your Lambda function is async but your code uses callbacks. By the time the callback is reached, your function has already been terminated because it ran asychronously.
Rather than using the outdated, confusing callback approach, just stick with async/await. The AWS SDK for Node.js already provides a .promise() method which you can call on asynchronous methods that use a callback, making it seamless to await on them.
That said, change your code to:
const dynamodb = new AWS.DynamoDB.DocumentClient({apiVersion: '2012-08-10', region: 'eu-west-1'});
exports.handler = async (event) => {
const params = {
TableName : "DontMissAPlaceTable",
KeyConditionExpression: "Partition_Key = :id",
ExpressionAttributeValues: {
":id": "media_001"
}
};
return {
statusCode: 200,
body: JSON.stringify(await dynamodb.query(params).promise())
}
};
Since you are already using the DocumentClient API, you don't need to specify the types ("S", "N", etc) when querying.
Also, make sure that Partition_Key really is your partition key. You use the name you defined in your table, no HashKey nor PartitionKey, meaning if you called your Hash Key id, then id should be used.
I've created apis in nodejs to scan and query dynamoDB table(contains 70K records).
I'm stuck with scan api. I've two APIs for scan -
1. Scanning table with limit of 500 - getting proper response
2. Scanning table without any limit - response code 403
And if I'm calling the same query without any limit through cli, getting full response.
Not getting what's the problem.
api.get('/deviceData', function (request) { // GET all users
return dynamoDb.scan({
TableName: 'student',
Limit: 500
}).promise()
.then(response => response.Items);
});
api.get('/deviceData-scan', function (request) { // GET all users
return dynamoDb.scan({
TableName: 'student'
}).promise()
.then(response => response.Items);
});
Please check how to use scan multiple time its help you.
function getData() {
let params = {
TableName: 'student'
};
let finalResult = [];
let queryExecute = function () {
documentClient.scan(params, function (err, result) {
if (err) {
console.log('failure', err);
} else {
finalResult = finalResult.concat(result.Items);
// check if more data exists.
if (result.LastEvaluatedKey) {
params.ExclusiveStartKey = result.LastEvaluatedKey;
queryExecute();
} else {
console.log('all data', finalResult);
}
}
});
};
queryExecute();
},