Can't delete items from Mongo Database in Meteorjs - javascript

I have created an object in Meteorjs to hold the database info for N numbers of dice rolls, and then the dice are displayed using handlebars #each iterator. Here is some of my code:
The global Mongo collection:
Items = new Meteor.Collection('items');</code>
When I roll the dice, this is what happens to the collection when a button is clicked:
//Don't want to bore you with all code, so here's just important parts...
var randomNumber=Math.floor(Math.random() * numSides) +1);
var numDice = 6;// It's really a variable passed in, but for here it's 6.
for (var i = 0; i < numDice; i++) {
Items.insert(item: randomNumber)
};
And then they display the info as dice because it displays numbers that I have CSS'd to look like Dice. But I'm straying here... Anyway, the dice rolling is awesome, but I want to clear the dice when I roll again. right now, they just keep adding up. And when I try to use any method to delete Mongo DB Items stuff, it crashes my app. Since I'm not sure how to debug very well yet in a browser, I need some help, and I'mm going to ask it here...
Now, my main problem is, when the dice are rolled again, I want to purge the database and start again. I am new to JavaScript and Meteor, and come from Java && Ruby land, so any suggestions are greatly appreciated.
I've tried
Items.removeIndexes(),
Items.purge(),
Items.remove({})
They all just freeze my app, and the numbers I displayed in the #each iterator are still there. I thought it would delete the stuff, and push the changes... No??? Please help.
The code is on GitHub # http://www.github.com/rabbitfighter81/DMware/

You should use the remove method, but if you call it from the client, you can only remove one document per call, and the selector must refer to the documents _id field. So, here's an example to remove all the documents in a collection the client has:
TheCollection.find().forEach(function(doc){
TheCollection.remove(doc._id)
})

Related

Retrieve random key from firebase database

I face the problem that I have a list of keys inside my firebase database and I want to retrieve one random key out of it, without downloading all keys and selecting one in my own app. Downloading all keys with for example .once() is a big no go, especialy because I may up end with 10.000+ keys in the future and I dont want my firebase bills to explode, Im still a student with no budget at all.
I already researched this topic and found following answer for my question.
The problem with this is, that I can not use limitToFirst() and also limitToLast() in the same query, else I get following error:
[Unhandled promise rejection: Error: Query.limitToLast: Limit was
already set (by another call to limit, limitToFirst, or limitToLast).]
Also other people face the same problem like me and I generaly see that this question always gets much views but rather poor answers which are, like apperently in the case I mentioned earlier outdated, or just not for usage in Javascript and React-Native.
Additional informations: I have a counter for my keys so I know at every time how many keys are stored inside my database. Following picture shows my database entirely:
This is the part of my code which shows the mentioned error:
const numberOfUsers = await firebase.database().ref("usercounter").once("value").then(snapshot => {
return(snapshot.val()); //retrieve numbers of users from "usercounter"
});
const randomIndex = Math.floor(Math.random() * numberOfUsers) + 1; //"generating random number, excluding 0"
var ref = firebase.database().ref('users'); //ref to my users keys
await ref.limitToFirst(randomIndex).limitToLast(1).once('value').then(DataSnapshot =>
{
//This is the query that does not work at all.
console.log(DataSnapshot.val())
});
Incase there is a way to overcome that problem, please let me know.
I would solve that problem this way:
Create for each list element a value with the field name id or some other you want. It should be a simple integer. Idealy incrementaly growing with the list. You could use the counter to increase the value each time you add an element.
When trying to get a random element from the list first get a random integer between 0 and the total count of all elements. Then use this query to get a single random element:
firebase.database().ref("users").orderByChild("id").startAt(randomNumber).limitToFirst(1);
Even if you don't hit the id with the randomNumber you would the neareas next element. This should be able to scale to any size.
The most diffictult part would be to optain the id incrementaly without repeating them. I would use for that an cloud function that does it when an item is added. Even a combination with the counter would be interesting.

my local storage fails to save, no idea why, first time using it

i got this function that's executed upon other things upon page load,
it does save the items correctly till the page is refreshed,
i want to use that array to calculate maximum score from it on future games,
some explanation would help
first time using JSON aswell
the code:
localStorage.setItem("scroes", JSON.stringify(gBestScores));
var retrievedData = localStorage.getItem("scroes");
gscores = JSON.parse(retrievedData);
gBestScores is an empty array that gets pushed a value each time the game ends or is restarted,
not saved in localstorage, checked and works fine,
gScores is an undefined variable at the top of the page, tried setting it to an empty array didnt make much difference
The code as it is doesn't load the scores up or save the scores properly.
It should be:
When the page / game load up, or before you need to display them or have them for insertion:
var retrievedData = localStorage.getItem("scores");
gscores = JSON.parse(retrievedData);
When the game ends:
// if game score is higher than the best scores, insert it into gBestScores
localStorage.setItem("scores", JSON.stringify(gBestScores));
Also, wouldn't you use the same array for the highest scores? Right now you are using two: gscores and gBestScores.

How to know how many items a Firestore query will return while implementing pagination

Firestore has this guide on how to paginate a query:
Firestore - Paginate data with query cursors
They show the following example:
Paginate a query
Paginate queries by combining query cursors with the limit() method. For example, use the last document in a batch as the start of a cursor for the next batch.
var first = db.collection("cities")
.orderBy("population")
.limit(25);
return first.get().then(function (documentSnapshots) {
// Get the last visible document
var lastVisible = documentSnapshots.docs[documentSnapshots.docs.length-1];
console.log("last", lastVisible);
// Construct a new query starting at this document,
// get the next 25 cities.
var next = db.collection("cities")
.orderBy("population")
.startAfter(lastVisible)
.limit(25);
});
QUESTION
I get the example, but how can I know how many items (in total, without the limit restriction) that query will return? I'll need that to calculate the number of pages and control the pagination component, won't I?
I can't simply display next and back buttons without knowing the limit.
How is it supposed to be done? Am I missing something?
You can't know the size of the result set in advance. You have to page through all the results to get the total size. This is similar to not being able to know the size of a collection without also recording that yourself somewhere else - it's just not scalable to provide this information, in the way that Cloud Firestore needs to scale.
this is not possible, the iterator cannot know how many documents it contains, as they are fetched via a gRPC stream.
But there is a workaround... but you have to make a few stuff:
1) write a counter in a firebase doc, which you increment or decrement everything you make a transaction
2) store the count in a field of your new entry, like position 10 or something.
Then you create an index on that field (position DESC).
This way you can do a skip+limit with a where("position", "<", N).orderBy("position", DESC)
It's complex but it does the trick

How to remove all items of a Mongo collection

I have seen that to remove all items of a Mongo collection using JavaScript I should use :
DockerStats.remove(); //where DockerStats is my collection
So my goal is to purge the DB every 20sec so I did the following code :
setInterval(Meteor.bindEnvironment(function(){
DockerStats.remove();
console.log("ok")
}),20000);
But when I start the app I had +/- 1000items then despite the terminal wrote 2 times "ok" I still have more than 1000items so it doesn't work because even if I check right after the "ok" I have more than 1000items and the number is always growing up.
So maybe I'm removing the items with the wrong way ?
According to the docs, you need to pass in an empty object to delete the whole collection. So, the below would remove all students from the Students collection:
Students.remove({})
I think this is because if you want to remove everything and start over you would use the drop method and recreate it, which the docs says is more performant.

ArrayCollection (Collection of forms) index collision in Symfony 2

I am using Symfony2 to build up my page.
When I try to update a collection of forms (like described in the cookbook entry "How to Embed a Collection of Forms"), i get a collision of the indexes of the frontend and the indexes of the ArrayCollection in the backend.
I've got the relation User <-> Address (OneToMany). A user wants to create/update/delete his addresses, therefore he can add / delete in the frontend with the help of the javascript part new address elements. He does the following:
(1) Adds new address (has index: 0)
(2) Adds new address (has index: 1) and instantly removes this address again
(3) Adds new address (has index: 2).
When he clicks on save button, the following code saves/updates the user (and its addresses):
$this->em->persist($user);
$this->em->flush();
New addresses for example are then correctly persisted to the database.
Now the user wants to update the address e.g. with index 0.
When he now clicks on the save button, it updates the adress with "index 0", but at the same time, it adds again the address with "index 2" to the database (object).
To better understand the problem, i've drawn a small illustration (handmade, sorry for my bad art skills):
Now , i've got two times the address with "index 1" within my object / database.
I know why this happens, it's because the first "index 1" address gets mapped to the ArrayCollection element "number 1", and the second gets mapped to "number 2 "(because of the frontend name "index 2").
You can say: "it just fills up the addresses, until it reaches the frontend index in the backend"..
But how can I fix this behaviour ?
Site note:
This behaviour occurs using ajax requests, because if you would reload the page after clicking "save button", it would reindex the addresses in the frontend correctly with the indexes in the backend.
My suggestion to handle that situation:
Reindexing the frontend indexes after clicking save with the server side
indexes. Is this a clear / the only solution for my problem?
Yes, this is problem of Symfony form collection and it has no easy solution imho. But I have to ask why don't you do exactly the same thing what page refresh does? You can refresh only html snippet with collection. HTML code for snippet can come from server-side. Back to your question - yes, reindexing is good solution until you do not want to try write custom collection type on your own.
symfony/symfony/issues/7828
There is similar problem with validating in collection - symfony/symfony/issues/7468.
Well I think default collection type and the tutorial in Symfony docs has the some drawbacks. Hope that's help.
I have come round this issue on the client side by modifying the Javascript/Jquery code given in the Symfony Documentation.
Instead of numbering the new elements by counting the sub-elements, I am looking at the last element's id and extracting its index with a regular expression.
When adding an element, I am incrementing the last index by 1. That way, I never use the same index.
Here is my code :
// Initializing default index at 0
var index = 0;
// Looking for collection fields in the form
var $findinput = $container.find(':input');
// If fields found then looking for last existing index
if ( $findinput.length > 0 ) {
// Reading id of last field
var myString = $findinput.last().attr('id')
// Setting regular expression to extract number from id containing letters, hyphens and underscores
var myRegex = /^[-_A-Za-z]+([0-9]+)[-_A-Za-z]*$/
// Executing regular expression on last collection field id
var test = myRegex.exec(myString);
// Extracting last index and incrementing by 1
if (test.length > 0) index = parseInt(test[1]) + 1;
}
I ran into this problem a couple of times during the past two years. Usually, following the Symfony tutorial How to Embed a Collection of Forms does the job just fine. You need to do a little bit javascript coding to add the "edit/update" functionality, but other than that - you should be just fine using this approach.
If, on the other hand, you have a really complex form which uses AJAX to validate/save/calculation/business logic/etc, I've found it's usually a better to store the final data into an array in the session. After submitting the form, inside the if($form->isValid()){...} block, you would have
$collection = new ArrayCollection($mySessionPlainArray);
$user->setAddress($collection);
I would like to warn you to be careful with the serialization of your data - you might get some awkward exceptions or misbehavior if you're using entities (see my question).
I'm sorry I can't provide more code, but the solution to this problem sometimes is quite complex.

Categories

Resources