How to append to a list/array in dynamodb? - javascript

For an 'id' in my DynamoDB table (e.g. e5eb02ae-04d5-4331-91e6-11efaaf12ea5), i have a column called Weather
['sun', 'rain', 'snow', etc...]
I need to update Weather when, say ['hail'] arrives. Right now, my update() below, replaces the the entire array. All i want to do is append 'hail' to the end of that list.
const updateinfo = {
id: "e5eb02ae-04d5-4331-91e6-11efaaf12ea5",
Weather: "hail"
}
try {
await API.graphql(graphqlOperation (UpdateInfo, { input: updateinfo })) //mutation
console.log('success')
}
catch (err) {
console.log(err)
}
How do i do this, ensuring that my list is just appended to with the info, WITHOUT having to get() and pull down ['sun', 'rain', 'snow', etc...], then adding 'hail' and creating a new array? Thats then a GetInfo() and an UpdateInfo() which is double the effort/call/expense.

I posted a response to a similar question in another question. The answer to this is to use a DynamoDB function called list_append.
list_append (operand, operand)
This function evaluates to a list with a new element added to it. You can append the new element to the start or the end of the list by reversing the order of the operands.
You can look here for a detailed response on how to do it using AWS AppSync and AWS Amplify.
https://stackoverflow.com/a/57088993/11681626

Related

Getting values from single Firebase Firestore Document

This is definitely a newbie question, and in part answered in the Firebase documentation, but for the life of me it's not working when implementing it in my own code - so I'm hoping the community can help me understand what I am doing wrong, and how to fix it.
When getting documents from Firestore, I can't access the actual values within, due to its structure, so when setting e.g. "var name = doc.name" it just gives me undefined. For getting MULTIPLE documents, I've already found apiece of code that works:
// Getting the document
docRef.collection(collectionRef).get()
.then((snapshots) => cleanData(snapshots))
.then((items) => items.map((item) => sampleFunction(item)));
// Firebase Utility cleaning documents (array)
function cleanData(snapshots) {
let data = [];
snapshots.forEach(function(doc) {
data.push({
id: doc.id,
...doc.data()
});
});
return data;
}
But when using this piece of code with e.g. collection("x").doc("id"), then it throws the error:
"Uncaught (in promise) TypeError: snapshots.forEach is not a function"
So I went ahead to modify the function as follows:
// Firebase Utility cleaning document (single)
function cleanDoc(snap) {
let data = [];
data.push({
id: doc.id,
...doc.data()
});
return data;
}
But that gives me "undefined" when attempting to access the values in my function again...
The documentation (in the city example) says to define a class. When I did that, I was able to get values from one document, but it gave me undefined the second time I called the same function on one page.
For context, I'm trying to display a User Profile, which displays people they work with on a project, which means I call these profiles as well, the data structure just callsa reference to the "worked with" profiles, and I get their ID's just fine, but when attempting to render an HTML item for each, the values within their profiles are undefined....Its confusing the hell out of me anyways.
If your function is an async function:
collectionSnap = await docRef.collection(collectionRef).get();
val items=[]
await Promise.all(querySnap.docs.map(async (doc) => {
// Do your your work and populate items
}));
// Do your work with items
You can try this approach to processing your documents.

Why doesn't strapi's `find()` query return an array?

Context
I have a front end app that requires an array of blog posts from the API, and when you call http://strapi-url/posts/ with a GET request, it returns all the results as objects in an array. Happy days.
Problem
Eventually I want to have more complex GET options with query params, so I need to modify the post controller and write a custom function for find().
When I modify the find() function in api/post/controllers/post.js , and just make it return the result of strapi.query('post').find(), it returns an object with keys rather than an array.
Code
async find(ctx) {
let entity = await.strapi.query('post').find();
return sanitizeEntity(entity, { model: strapi.models.post });
},
I know I could simply convert it into an array in the front end, but feels like a messy solution, and I would rather understand why it doesn't return an array, and what would be the best way to approach a solution.
The code in sanitizeEntity actually does this. You can check it out in the source code(node_modules/strapi-utils/lib/sanitize-entity.js). Also you can see this by dropping the sanitizeEntity row - you will get an array from await.strapi.query('post').find().
You can run the following test (add a custom endpoint) to see the results:
async test2(ctx) {
let entity = await strapi.query('post').find();
ctx.send({
message: 'okay',
posts: entity,
sanitizedPosts: sanitizeEntity(entity, { model: strapi.models.post })
}, 200);
}
You can solve it by making your own custom sanitize function which returns an array OR by processing the result before returning it like so:
let entity = await strapi.query('post').find();
let sanitizedEntity = sanitizeEntity(entity, { model: strapi.models.post });
//process sanitized results to an array
//return the result as array

I would like to update MongoDb document

my problem is to update a specific field of the document.
Let's imagine we have multiple input fields when I am just changing one of the field of the document the rest of them going to be null since I am just updating one of them. Is there any simple way to update one field and the rest field not changed.
I can give a switch case or if-else but I do not think it is an
appropriate way to solve this kind issue.
updateChr:async ( args: any) => {
try {
const data = await Client.findByIdAndUpdate(args.clientId,
{$set:
{
chronology:{
status: args.clientInput.status,
note:args.clientInput.note,
date: args.clientInput.date,
file:{
filename:args.clientInput.file.filename,
data:args.clientInput.file.data,
type:args.clientInput.file.type,
size:args.clientInput.file.size,
}
}
},
}
,{useFindAndModify: false})
return transformClient(data);
} catch (err) {
throw err;
}
},
So this part right here is what you need to pay attention to:
{$set:
{
chronology:{
status: args.clientInput.status,
note:args.clientInput.note,
date: args.clientInput.date,
file:{
filename:args.clientInput.file.filename,
data:args.clientInput.file.data,
type:args.clientInput.file.type,
size:args.clientInput.file.size,
}
}
},
}
What you're telling mongo is that, no matter what's in those fields now (or even if they don't currently exist), to set their new values to what you are providing. If you're providing a null value, then it will set its new value to null. If you aren't wanting to update things if their new value is null, then you'll need to clean up your data prior to pushing it to mongo. The easiest way to do this is to sanitize the data prior to adding it to the object you're referencing above. Once you've only got the data that actually exists there, then just loop over the data to create the update object for mongo rather than statically setting it like it is here.
Alternatively, if the data that actually should exist in those fields is available at this stage, you could loop over the null values and fill them in with the current values in mongo or whatever they should be.

Updating firestore using previous state

Is it possible to update firestore using the previous state?
So for example I have an address document which has a users field which holds an array of users associated with the address.
whenever I want to add a new user to this array I need the previous array otherwise I will end up overwriting the current data with the new data.
So I end up with something like.
firestore()
.collection("addresses")
.doc(addressId)
.get()
.then(doc => {
this.db
.collection("addresses")
.doc(addressId)
.update({
users: [...doc.data().users, id]
})
});
Is there a way to access the previous data without having to nest calls?
if not
Is there a better way to manage relationships?
If you need the previous value to determine the new value, you should use a transaction. This is the only way to ensure that different clients aren't accidentally overwriting each other's actions.
Unfortunately transactions also need nested calls, since that is the only way to get the current value, and even have one extra wrapper (for the transaction.
var docRef = firestore()
.collection("addresses")
.doc(addressId);
return db.runTransaction(function(transaction) {
// This code may get re-run multiple times if there are conflicts.
return transaction.get(docRef).then(function(doc) {
transaction.update(docRef, { users: [...doc.data().users, id ]});
});
}).then(function() {
console.log("Transaction successfully committed!");
}).catch(function(error) {
console.log("Transaction failed: ", error);
});
The optimal solution is to use a data structure that doesn't require the current value to add new values. This is one of the reasons Firebase recommends against using arrays: they're inherently hard to scale when multiple users may be adding items to the array. If there is no need for maintaining order between the users, I'd recommend using a set-like structure for the users:
users: {
id1: true,
id2: true
}
This is a collection with two users (id1 and id2). The true values are just markers, since you can't have a field without a value.
With this structure, adding a user is as easy as:
firestore()
.collection("addresses")
.doc(addressId)
.update({ "users.id3": true })
Also see the Firestore documentation on
Working with Arrays, Lists, and Sets

Setting unique id with Meteor insert

I'm linking the FB Graph API to Meteor so that I can retrieve a users photos and I'm having trouble setting the Meteor id to the Facebook id for each photo. Right now when the function is called it will return the same photo multiple times in the database since Meteor assigns a new _id to each photo each time.
For example, one entry might look like this:
Object {_id: "cnMsxSkmMXTjnhwRX", id: "1015160259999999", from: Object, picture: "https://photoSmall.jpg", source: "https://photoBig.jpg"…}
And a second, after the call has been performed again, like this:
Object {_id: "acMegKenftmnaefSf", id: "1015160259999999", from: Object, picture: "https://photoSmall.jpg", source: "https://photoBig.jpg"…}
Thereby creating two id fields in MongoDB.
The code I am using is below. I've tried a number of things to fix the code to no avail.
Meteor.methods({
getUserData: function() {
var fb = new Facebook(Meteor.user().services.facebook.accessToken);
var data = fb.getUserData();
_.forEach(data.data, function(photo) {
Photos.insert(photo, function(err) {
if(err) console.error(err);
});
});
}
});
Thanks in advance!
Check if the photo exists prior to inserting it
...
_.forEach(data.data, function(photo) {
if(Photos.findOne({id: photo.id})) return;
...
Another option is to add a unique key index to the id field. Or even use the _id field to store the id value. (be sure to use try catch to ensure it doesn't cause an error on the second insert).
Wouldn't there be something different to each of these with different ids?
You could also clean up the uniques before you run them with _.uniq

Categories