MongoDB weird behavior needs explanation - javascript

So yesterday I started messing around with MongoDB in Node and when it comes to retrieving data I encountered a weird practice.
You retrieve data from a collection that is nested within a database by calling.
data = client.db([dbname]).collection([collectionname]).find([searchcriteria])
and this returns what seems to be an object at least in the eyes of typeof
the sample code then uses the following lines to log it to the console:
function iterate(x){
console.log(x)
}
data.forEach(iterate)
The output is as expected in this case two objects with 2 pairs everything is fine so far.
I thought it is a bit unnecessary to have the iterate function so I changed that to just
console.log(data)
expecting the 2 objects in a array or nested in another object but what i get is this huge object with all kinds of different things in it EXCEPT the two objects that we saw before.
So now to my Question and what I need deeper explanation on:
why can i actually use .forEach() on this object I cannot recreate this on other objects.
and the second thing is why is console.log(data) giving me all this output that is hidden if I call it through .forEach()?
and is there any other way to quickly within one or 2 lines of code retrieve data from Mongo ?
this seems to be a very not useful way of doing things.
and how does this .forEach() thing on objects work I found a article here on stack however this was not very detailed and not very easy to understand.

The find function returns a cursor - this is the huge object that you are seeing. Checkout documentation for more details here: https://docs.mongodb.com/manual/reference/method/db.collection.find/#db.collection.find
The reason why you can call forEach on the returned object (=cursor), is because it is one of its methods. See https://docs.mongodb.com/manual/reference/method/cursor.forEach/#cursor.forEach
Overview of all cursor methods is here: https://docs.mongodb.com/manual/reference/method/js-cursor/
To get the array of data that you are looking for you need to use the toArray method, like so:
const data = client.db([dbname]).collection([collectionname]).find([searchcriteria]).toArray()

Related

Angular: How to map an array of 'mat-checkbox's to get strings associated with the checked checkboxes

To preface, I have found a solution that works for me in the situations I have tried it, but I am fairly new to javascript and RXJS and don't fully understand what the solution is doing so I can't be sure if it will work in every instance.
I am using reactive forms and have arrays of checkboxes, what I would like to do is get an array of all of the keys used to generate the checkboxes, but without any of the unchecked boxes. Ideally, I could use this to return additional values as well such as a user-readable string, but that is far from important as I can do that in a separate step fairly easily. I have come up with a few methods of my own, but they don't seem to be very robust or performant.
I would have replied on this thread, but I lack the reputation.
This is the best solution I have found, which I would be totally happy to use, but I don't have much experience with RXJS or maps in javascript so I am not totally sure what it is doing:
this.controlNames = Object.keys(this.checkboxGroup.controls).map(_=>_); //This seems to just produce an object of control keys as properties and their value
this.selectedNames = this.checkboxGroup.valueChanges.pipe(map(v => Object.keys(v).filter(k => v[k]))); //Some sort of magic happens and an array is generated and contains only the keys whose values are 'true'
I have tried breaking that snippet apart and using console.log to test what it is doing in each step, but it really didn't give me much useful information. Any advice or or better ideas would be thoroughly appreciated, there seem to be a lot of conventions in javascript that people adhere to and it can be hard to sort through what is a convention and what is actually doing something.
I think I found a way to break it down and get a grip on it and want to post my explanation for anyone who comes looking.
In this part, it is just creating an iterable map of the 'checkboxGroup.controls' object. This could have been used to loop over in the template and make all of the checkboxes. Since my form structure is already generated from arrays of objects with known properties, I don't need this. The underscores aren't doing anything special here, people just like to use them for private variables.
this.controlNames = Object.keys(this.checkboxGroup.controls).map(_=>_);
For those who are new to arrow functions or some of the conventions of javascript, the code above is not quite, but essentially shorthand for this:
this.controlNames = [];
Object.keys(this.checkboxGroup.controls).forEach(function(key) {
this.controlNames.push(key);
}
I have changed the short variables to longer ones to make them easier to understand in this second part. This maps the value changes observable as an iterable 'changesObj', retrieves the keys, and filters the keys by instances where the key has a true value. The code filter(key => changesObj[key]) returns the key if the key is not null, undefined, or false.
this.selectedNames = this.checkboxGroup.valueChanges.pipe(map(changesObj => Object.keys(changesObj).filter(key => changesObj[key])));
This is essentially just shorthand for this:
function propNotFalse (changes, prop) {
return changes[prop] == true;
}
this.selectedNames = this.alternateFilter = Object.keys(this.checkboxGroup.valueChanges).filter(this.propNotFalse.bind(null, this.checkboxGroup.valueChanges));

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.

Riak MapReduce in single node using javascript and python

I want to perform MapReduce job on data in Riak DB using javascript. But stuck in very begining, i couldnot understand how it is returning value.
client = riak.RiakClient()
query = client.add('user')
query.map("""
function(v){
var i=0;
i++;
return [i];
}
""")
for result in query.run():
print "%s" % (result);
For simplicity i have checked the above example.
Here query is bucket and user contain five sets of data in RiakDB.
i think map() returns single value but it returns array with 5 value, i think equivalent to five set of data in RiakDB.
1
1
1
1
1
And here, why I can return only array? it treats each dataset independently, and returns for each. so i think i have five 1's. Due to this reason when i process fetched data inside map(), returns gives unexpected result for me.
so please give me some suggestion. i think it is basic thing but i couldnot get it. i highly appreciate your help.
When you run a MapReduce job, the map phase code is sent out to the vnodes where the data is stored and executed for each value in the data. The resulting arrays are collected and passed to a single reduce phase, which also returns an array. If there are sufficiently many results, the reduce phase may be run multiple times, with the previous reduce result and a batch of map results as input.
The fact that you are getting 5 results implies that 5 keys were seen in your bucket. There is no global state shared between instances of the map phase function, so each will have an independent i, which is why each result is 1.
You might try returning [v.key] so that you have something unique for each one, or if the values are expected to be small, you could return [JSON.stringify(v)] so you can see the entire structure that is passed to the map.
You should note that according to the docs site javascript Map Reduce has been officially deprecated, so you may want to use Erlang functions for new development.

How do I directly assign values to an array but use push method on OOB exception?

It is my understanding that -- from a performance perspective -- direct assignment is more desirable than .push() when populating an array.
My code is currently as follows:
for each (var e in Collection) {
do {
DB_Query().forEach(function(e){data.push([e.title,e.id])});
} while (pageToken);
}
DB_Query() method runs a Google Drive query and returns a list.
My issue arises because DB_Query() can return a list of variable length. As such, if I construct data = new Array(100), direct assignment has the potential to go out of bounds.
Is there a method by which I could try and catch an Out of Bounds exception to have values directly assigned for the 100 pre-allocated indices, but use .push() for any overflow? The expectation here is that an OOB exception will not occur often.
Also, I'm not sure if it matters, but I am clearing the array after a counter variable is >=100 using the following method:
while(data.length > 0) {data.pop()}
In Javascript, if you set a value at an index bigger than the array length, it'll automatically "stretch" the array. So there's no need to bother with this. If you can make a good guess about your array size, go for it.
About your clearing loop: that's correct, and it seems that pop is indeed the fastest way.
My original suggestion was to set the array length back to zero: data.length = 0;
Now a tip that I think really makes a performance difference here: you're worrying with the wrong part!
In Apps Script, what takes long is not resizing arrays dynamically, or working your data, that's fast. The issue is always with the "API calls". That is, using UrlFetch or Spreadsheet.Range.getValue and so on.
You should take care to make the minimum amount of API calls possible and in your case (I'm guessing now, since I haven't seen your whole code) you seem to be doing it wrong. If DB_Query is costly (in API calls terms) you should not have it nested under two loops. The best solution usually involves figuring out everything you'll need before-hand (do as many loops you need, if it doesn't call anywhere), then pass all parameters to do a bulk operation and gather it all at once (in one API call), even if it involves getting more data than you needed. Then, with the whole data at hand, loop through and transform it as required (that's the fast part).

How to convert json/object to array for looping

I have a javascript application, that calls an api, and the api returns json. With the json, I select a specific object, and loop through that.
My code flow is something like this:
Service call -> GetResults
Loop through Results and build Page
The problem though, is sometimes that api returns only one result, so that means it returns an object instead of an array, so I cant loop through results. What would be the best way to go around this?
Should i convert my object, or single result to an arrary? Put/Push it inside an array? or should I do a typeof and check if the element is an array, then do the looping?
Thanks for the help.
//this is what is return when there are more than one results
var results = {
pages: [
{"pageNumber":204},
{"pageNumber":1024},
{"pageNumber":3012}
]
}
//this is what is returned when there is only one result
var results = {
pages: {"pageNumber": 105}
}
My code loops through results, just using a for loop, but it will create errors, since sometimes results is not an array. So again, do I check if its an array? Push results into a new array? What would be better. Thanks
If you have no control over the server side, you could do a simple check to make sure it's an array:
if (!(results.pages instanceof Array)) {
results.pages = [results.pages];
}
// Do your loop here.
Otherwise, this should ideally happen on the server; it should be part of the contract that the results can always be accessed in a similar fashion.
Arrange whatever you do to your objects inside the loop into a separate procedure and if you discover that the object is not an array, apply the procedure to it directly, otherwise, apply it multiple times to each element of that object:
function processPage(page) { /* do something to your page */ }
if (pages instanceof Array) pages.forEach(processPage);
else processPage(pages);
Obvious benefits of this approach as compared to the one, where you create a redundant array is that, well, you don't create a redundant array and you don't modify the data that you received. While at this stage it may not be important that the data is intact, in general it might cause you more troubles, when running integration and regression tests.

Categories

Resources