What's the difference between these two functions - javascript

So i have an json array named users. Im trying to update an individual field if id comes from request equals to users id. When i use for loop it works but it doesn't when i try to use forEach (there are no errors). I don't understand the difference between these two.

In the forEach, user is just a variable that happens to start with the value passed in as a parameter to your lambda function. Setting user = ... doesn't actually change anything in the original array. Nor does it change the properties on the object that is currently in that array.
Consider using Object.assign() instead:
Object.assign(user, req.body);

Related

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
});

JS is changing 2d-array values, might it be another function interfering?

Short summary: I have written some code that fills up a 2-dimensional array. When I display this array, everything is perfect. Now I give this 2d-array as a parameter to a function. When I call the function inside of
document.getElementById('output').innerHTML = myFunction(int, array);
it shows exactly the right values. However, I don't want to display them, I want to further use them. As the function returns an array (one dimensional), I tried
var my_result_array = myFunction(int, array);
I have also tried push() and pre-defined arrays or accessing just single elements.
The thing is, as soon as I have the function called in my document, the array I am giving to the function as a parameter is changing! I took care that there are no similiar names, but I just can`t figure out, why it is always changing my parameter array, therefore destroying the calculation but working fine if I use it in the document.getElementbyId part.
Any suggestions?
Edit for more code:
I try to keep it short and explainatory. I am creating an empty array with a dimension given by mat_dimension_js
var berechnungs_array = new Array(mat_dimension_js);
for (var i = 0; i < mat_dimension_js; i++){
berechnungs_array[i] = new Array(mat_dimension_js);
}
I then fill this array up with values. If I print the array, everything is fine, the values are where they belong. I then feed this array to myFunction()
Sorry for the mess, I have also tried it without creating an array A again.
I then try to grab the output of myFunction() as told above, but as soon as I do that, somehow the array I have given as a parameter changes.
Arrays in JavaScript are passed by reference, meaning that any changes you do to the array passed inside the function will also be saved in the actual array.
In addition, A = mat_array; does not create a copy of mat_array, but another pointer to it (meaning that both variables refer to the exact same array object internally).
To properly make a copy of a 1D array, calling .slice(0) should do the trick. However, for 2D arrays, you need to do this recursively.
See Javascript passing arrays to functions by value, leaving original array unaltered
What is the most efficient way to deep clone an object in JavaScript?

How do I iterate through objects stored in a firebase array in JavaScript?

At the moment I am storing a few objects in Firebase. After successfully retrieving the items from Firebase and storing them in a firebaseArray, I want to further thin out the unwanted elements by deleting the elements in the firebaseArray that do not have the desired property. Consider my code at the moment, that does not do as wanted, however there are no errors in the console:
var querylatestPosts = firebase.database().ref("Topics");
$scope.latestPosts = $firebaseArray(querylatestPosts);
console.log($scope.latestPosts) ;
$scope.latestPosts.forEach(function(el) {
if ($scope.checkWorldview(el) == false) {
delete $scope.latestPosts.el ;
}
});
(Note I am unable to log 'el' in the console, nor does the forEach seem to execute, as I can log nothing in the function in the console)
The 'checkWorldview' function behaves as expected when elements are fed in different instances and returns false if the required property is not present in the element under consideration. Thus if the function returns false, I want to delete the specific element in $scope.latestPosts that does not contain the wanted property.
I hope this is clear, thank you in advance for any help you can offer!
The way you are using the $firebaseArray isn't recommended by the docs (see here), which state that $firebaseArray is read only and should not be manipulated.
So you have a few options:
Instead of filtering the array on the client-side, you should modify the query you're using to retrieve data from Firebase to only get elements that have the desired property (ex: use 'equalTo' in the query)
OR
Don't use a $firebaseArray because you're not using it in the way it was intended. Use a regular, good ol' fashion JavaScript array instead.
** Also, just a general comment: don't delete elements from an array as you loop through it as this is generally bad practice (we don't expect arrays to have elements added/removed while we loop through them). Instead, use Array.filter.

Return the result of a method in a QuerySet.values() or values_list()?

When calling .values() or .values_list() on a QuerySet you can pass in the specific fields you want returned, or even fields you want from related tables. What I'm wanting to do is include the result of a method defined on the model, in addition to some fields, for example:
class MyModel(models.Model):
name = models.CharField()
def favouriteNumber(self):
return random.randint(1,10)
list(MyModel.objects.all().values('name','favouriteNumber'))
=> [{'name':'Bob', 'favouriteNumber':6}, {'name':'Fred', 'favouriteNumber':4}]
The above doesn't work, but is what I'm wanting to do, in the same way that the templating language can treat model methods without parameters just like fields.
The reason I'm wanting to do this is so that I can pass the information to the JavaScript in the front end to use instead of making calls back to the server to retrieve it each time.
Assuming the above (or something similar) isn't possible, I know I could loop over my values() result afterwards and add in the extra information manually.. what would be the most efficient (and clean) way to do that?
You might want to try using only() instead of values(). Like values() it will only fetch the specified fields from the database, but unlike values() it will return actual instance objects that you can call methods on.
That way, whether you're looping in the view or the template, you can access the method in addition to the specified fields.
If you need dictionary-like structures (for json.dumps(), say) you can just construct them in a comprehension:
instances = MyModel.objects.only('name')
data = [{'name': instance.name,
'favourite': instance.favouriteNumber()} for instance in instances]

How can I get the key as well as the value when using db.js to query IndexedDB?

I have an IndexedDB of changes. I add an item like this, and then log the result to check the key has been created successfully:
_this._idb.add('steps', step).done(function (items) {
var item = items[0];
_logger.log("ADDED STEP", { id: item.__id__, step: item }, "CT");
});
The output from this is as expected:
...as you can see, the id has been added to the object when it is stored.
However, when I query the db to getback a list of objects, using this code:
this._idb.steps.query('timestamp').bound(start, end).execute().done(function (results) {
_logger.log("Results", results, "CT");
}
I don't get the id as part of the object that is returned:
... and the lack of id makes updating and deleting impossible.
How can I get the id of the item when I query indexed db using db.js - or am I approaching this in the wrong way, and is there something else I should be doing?
(Note: I'm using TypeScript to compile the JS, but I don't think that's especially relevant to this question)
This is expected behaviour, you're only going to get the __id__ property if you don't define a keyPath in your db schema.
Because there's no keyPath defined the value is not associated with it in indexeddb, it's only added to the resulting object after it has been added, because at that point in time we know the auto-incremented value that IndexedDB has assigned to it.
Since the value isn't really part of the object I don't have any way to assign it to the object when it comes out during a query, maybe I could use the position in the array but that's more likely to be wrong than right.
If you want the ID to be persisted against the object then you need to define a keyPath as part of the object store schema and the property will be added to the resulting object and available and it will be on the object returned from a query.
Disclaimer - I wrote db.js
Looking at the source, __id__ is only defined when your keyPath is null in the add() method. From what I'm seeing, you'll never see this in a query() response.
In IDB null keyPaths are allowed only when using auto-incrementing ("out-of-line") keys. So if you're getting the object back, it should have an auto-incrementing key on it or some other keyPath.
The __ prefix in JavaScript usually means the developer intended it to be a "private" property. I'm guessing this is for internal use and you shouldn't be counting on this in your application code.
Consider using explicit, so-called "in-line" keys on your object store.
The goal of db.js is easy and simple to use. Your is advanced use case.

Categories

Resources