Firebase Update using a String Object - javascript

I am making a simple program to log in tasks, when someone updates the field, I would like to update the document with only what was updated, thus I made a string generator that would create the parameters :
function fireBaseUpdateStringMaker(update_field,update_val)
{
return '\''+update_field+'\''+' : '+'\''+update_val+'\''+','
}
which creates a field as such : 'update_field' : 'update_val'
Using this directly in my code works well if I follow the documentation from Firebase
db.collections('this_collection').doc('this_doc').update({ 'update_field' : 'update_val' })
but if I pass this to the update as a variable then it doesnt work
var updater = 'update_field' : 'update_val' ;
db.collections('this_collection').doc('this_doc').update({ updater })
I saw answers from other questions mentioned using square notation but using it here gives an error " ':' expected" , not putting the square notation creates a new field in my db called "updater" with content " 'update_field' : 'update_val' ".
Is there anyway to do this or should I simply just update every value everytime I'm editing a document? I'm quite new to NOSQL/Firebase so this is still not too intuitive for me. Any help is appreciated. thank you.

What you're doing isn't valid use of Firestore APIs. You can't compose a string of field/value pairs - the document data must be a JavaScript object. You have to populate a JavaScript object with the names of the fields a properties, along with their associated values.
This should work:
db.collection('this_collection').doc('this_doc').update({
field: "value"
})
If you want to compose the object separately, do so as normal in JavaScript:
const data = { field: "value" }
db.collection('this_collection').doc('this_doc').update(data)

Related

Trouble with accessing Firebase Cloud Firestore

I am using Cloud Firestore and am having some problems accessing a value in a simple database.
Here is how the database is structured
This is the code I am using to access the "basementER-status" field in the database.
//current status value is pulled from database
function getRawStatus ()
{
return db.collection("rooms").doc("roomsDoc").get().then(function(doc) {
console.log(doc.data());
console.log(doc.data().basementER-status);
return doc.data().basementER-status;
});
}
For the first console.log, this is printed to the console:
{1ER-status: 0, 2ER-status: 0, basementER-status: 0}
1ER-status: 0
2ER-status: 0
basementER-status: 0
__proto__: Object
This is the correct doc that needs to be brought from the database, so I know that part of my code is right.
However, the second console.log prints NaN to the console.
What is happening here? I don't understand. I've accessed fields like this before in cloud firestore and it has always worked.
For your second console.log statement, you are trying to access a specific parameter in an object, so you should use this:
console.log(doc.data()["basementER-status"]);
For more info, go here: firestore adding data link
The problem is because of the way JavaScript parses your statement. This line:
console.log(doc.data().basementER-status);
Is actually performing a mathematical subtraction between doc.data().basementER and the value of the variable status. That's not what you want.
If you want the value of a field with JavaScript operators or other special characters in it, you will have to use a different syntax:
const data = doc.data();
console.log(data['basementER-status']);
The square brackets let you provide an arbitrary string to look up the name property in the object.

How to increment a map value in a Firestore array

I have a firestore firebase database , in which I have a collection users
there is an array in the collection and in the array there is a map
in map there is a field qty.. I want to increment that qty value..
using increment doesnt help as the qty is inside a array index
db.collection("users").doc(checkId).update({
myCart: firebase.firestore.FieldValue.arrayUnion({
qty: firebase.firestore.FieldValue.increment(1),
}),
this is the error Output =>
Uncaught (in promise) FirebaseError: Function FieldValue.arrayUnion() called with invalid data. FieldValue.increment() can only be used with update() and set()
My answer below won't work, given that the qty is in an array. The only way to update an item in an array is to read the entire document, update the item in the array, and then write the entire array with the updated item back to the document.
An alternative would be to use a map instead of an array, and then update the qty using the approach outlined in my (old, and non-working) answer below 👇
You need to specify the full path to the field you're trying to update. So I think in your case, that'll be:
db.collection("users").doc(checkId).update({
"myCart.0.qty": firebase.firestore.FieldValue.increment(1)
}),
The field you want to update is embedded in an array. In this case, you can't use FieldValue.increment(), since it's not possible to call out an array element as a named field value.
What you'll have to do instead is read the entire document, modify the field in memory to contain what you want, and update the field back into the document. Also consider using a transaction for this if you need to update to be atomic.
(If the field wasn't part of an array, you could use FieldValue.increment().)
As of today (29-04-2020)... this is tested by me.
Suppose my data structure is like this:
collection: Users
Any document: say jdfhjksdhfw
It has a map like below
map name: UserPageVisits
map fields: field1,field2,field3 etc
Now we can increment the number field in the map like below:
mapname.field1 etc...
That is use the dot operator to access the fields inside the map just like you would do to an object of javascript.
JAVA Code (Android), update the field using transactions so they can complete atomically.
transaction.update(<documentreference object>,"UserPageVisits.field1",FieldValue.increment(1));
I have just pushed a version of my app which uses this concept and it's working.
Kudos !!
My Best Regards
Previous answers helped me as well, but dont forget about the "merge" property!!! Otherwise it will overwrite your entire array, losing other fields.
var myIndex = 0;
const userRef = db.collection('users').doc(checkId);
return userRef.update({
'myCart.${myIndex}.qty': admin.firestore.FieldValue.increment(1)
}, {
merge: true
});

Form a string in typescript with all attendees in Google Calendar API

I am trying to create an event using Google Calendar API using HTTP method.I am writing all my code in typescript.
Now, I have an array containing the email ids of all the attendees that we want to add to that event. So, to pass all those email ids of the attendees in a single query parameter, I am trying to form a single string in the exact format as that shown in API docs. But after forming the string, when I make the API request from server side code, it somehow passes unwanted backslash in that string.
I have tried forming a string by concatenating the keyword email which is to be sent in front of every email that I want to include as attendee. I tried using single backslash () as an escape sequence to insert double-inverted commas, but it didnt work.
I have also tried doing the same thing using join() function, but still unwanted backslashes get introduced in the string when I passed it as attendee parameter value in Create Event API call.
The expected format of string I need to pass in the API call is :
"attendees": [
{
"email": "xyz#gmail.com"
},
{
"email" : "abc#gmail.com"
}
]
The function I am trying to form the string is -
for (let index = 0; index < email_ids.length-1; index++) {
mapping = mapping + "{'email':"+"'"+email_ids[index]+"'}";
if((email_ids.length-1)!=index) {
mapping=mapping+ ",";
}
}
Here mapping is the string I am trying to form.
Now the problem is when I console.log this mapping string, it prints something like -
{'email': " xyz#gmail.com '} , {'email': " abc#gmail.com '}
which is exactly something I want to pass inside the attendee parameter. But when I read the logs of the API request that I sent, I see the parameter attendee to be something like -
"attendees":["{\'email\': \\" xyz#gmail.com \'} , {\'email\': \\" abc#gmail.com \'} "]
There are these unwanted backslashes that get introduced at every point of concatenation in my above function, and I want to remove these. I think this is the reason why I am creating a public event but it isn't adding the attendees to that event, so this adding attendees part is not working as expected.
Any help is appreciated. Thanks a lot in advance.
You seem to be generating a string, and passing this back to whatever method is sending the data. Like Dan D said in a comment, try creating an object instead, as it seems that's what the interface is expecting in the atendees[] field.
This also simplifies your code a lot:
const list = email_ids.map((id: string) => ({ email: id }));
This creates a full list. In on your code you skip the last item in email_ids. I'm assuming it's an error, but if not, you can do it this way:
const list = email_ids
.filter((_:string, i:number)=> i < email_ids.length -1)
.map((id: string) => ({ email: id }));
This will generate an Array with the objects, as in
[
{ email: "xyz#gmail.com" },
{ email: "abc#gmail.com" }
]
Also, notice your code seems to be transforming the data into an array somewhere already:
"attendees":["..."]
So to avoid an array inside of an array, you'll need to figure out what's going on and how to pass/receive the correct data. It's hard to say without looking at the whole lifecycle of that payload from generation to sending to the server.
Lastly: in general, there's no reason to generate JSON by hand. In fact, I can't think of a single reason where anyone would ever want or need to create a JSON source code directly. If you really need a string rather than ab object, creating an object (like above) and calling JSON.stringify() on it later is the right solution.

Object.assign not working as expected

I have one object called bookings, and inside it I have several properties, and i want extend with Object.assign, like this:
let data = Object.assign(booking, {
hiw: event.hiw[booking.locale],
tip: event.tip[booking.locale],
start: moment(event.start).format('L')
});
But when I print the data, the result will be the same object from the source (booking), so hiw, tip and start will be ignored, but... if I try to do:
let data = Object.assign({}, {
hiw: event.hiw[booking.locale],
tip: event.tip[booking.locale],
start: moment(event.start).format('L')
});
This will work perfect.
My question is: what am I doing wrong here? Why can't I extend booking and I can extend the empty object?
That's definitely not a problem with async code, when i try to extend booking, he already exist with all properties inside.
I also was trying to use underscore extend method, and the behavior is exactly the same.
Mongoose documents (model instances) are special: they will only print properties that are present in the schema.
If properties aren't defined there, they won't show up when you console.log() them (and also not if you convert the document to a plain JS object with obj.toObject()).
This means that using Object.assign() will only work if you assign properties that are also present in the schema. Any properties that aren't declared will not be shown (nor saved to the database).
If your intention is to use the document for output, you should convert it to a proper JS object first before assigning to it:
let data = Object.assign(booking.toObject(), {
hiw : event.hiw[booking.locale],
tip : event.tip[booking.locale],
start : moment(event.start).format('L')
});

Avoiding duplicate JS object properties from a single assignment operation?

I am running a script on a large dataset to expand existing information. e.g:
...
{
id : 1234567890
},
{
id : 1234567891
},
...
becomes
...
{
id : 1234567890,
Name : "Joe"
},
{
id : 1234567891,
Name : "Bob"
},
...
I am doing this via the following code:
for(var cur in members)
{
curMember = members[cur];
// fetch account based on curMember.id to 'curAccount'
if(curAccount != null)
{
curMember.DisplayName = curAccount.DisplayName;
}
}
For the most part, this works as expected. However, once in a while (in the order of tens of thousands of entries), the result looks like this:
...
{
id : 1234567891,
Name : "Bob",
Name : "Bob"
},
...
I now have data which is in an invalid format and cannot be read by the DB, since duplicate property names doesn't make sense. It is occurring for random entries when the script is re-run, not the same ones every time. I need either a way to PREVENT this from happening, or to DETECT that it has happened so I can simply reprocess the entry. Anyone know what's going on here?
EDIT: After further investigation, the problem appears to occur only when the objects being modified come from a MongoDB query. It seems that if code explicitly sets a value to the same element name more than once, the field will be duplicated. All elements of the same name appear to be set to the most recently specified value. If it is only assigned once as in my original problem, it is only duplicated very rarely. I am using MongoDB 2.4.1.
Got it all figured out. MongoDB has a bug up to shell version 2.4.1 which allows duplicate element names to be set for query result objects. Version 2.4.3, released just this Monday, has a fix. See https://jira.mongodb.org/browse/SERVER-9066.
I don't really get your problem. If you apply identical property names to an object in ECMAscript, that property will just get overwritten. The construct in your snippet, can never be exist in that form on a live-object (excluding JSON strings).
If you just want to detect the attempt to create a property which is already there, you either need to have that object reference cached beforehand (so you can loop its keys) - or -
you need to apply ES5 strict mode.
"use strict";
at the top of your file or function. That will assure that your interpreter will throw an exception on the attempt to create two identical property keys. You can of course, use a try - catch statement to intercept that failure then.
Seems like you cannot intercept errors which get thrown because of strict mode violation.

Categories

Resources