Updating MongoDB array from variable array in batch operation? - javascript

I am working in Node.js and am attempting to push or pull the contents of an array to my mongodb collection. Currently my [working] code to pull objects from the array in FieldArray looks something like this:
for (var i=0; i < MyList.length; i++) {
collection.update(
{field:"MyValue"},
{$pull: {FieldArray: MyList[i]}},
function(err, item){...}
);
}
I'm aware of the ability to use $push/$each, $addToSet/$each and $pullall but they don't seem to accept values dynamically from an array (or I haven't found any indication that it can). Basically, I'd like to be able to use this function with an array of one item or one hundred, using the appropriate batch calls.
Is there any way to make such a call without having to loop through a separate call on the database for each iteration?

You want $pullAll. It does exactly what you are trying to iterate over
collection.update(
{ "field": "MyValue" },
{ "$pullAll": { "FieldArray": MyList } }
)
If that doesn't work then then your array elements are not matching the structure used in your document. Make them that way.

Related

Not able to use sort() inside of map function

The documents in my couchdb look like this:
{
docType: "event",
tags: ["bb","aa","cc"],
...
}
I would like my couchdb view function, to emit a sorted array of tags, so I tried:
function(doc) {
if (doc.docType == 'event') {
if (doc.tags.length > 0) {
emit(doc.tags.sort(), doc._id);
}
}
}
But this (.sort()) is not working as expected: The result shows only documents, where the tags array has only one entity (tags.length = 1).
I found the answer by the help of the couchDB Slack channel. sort() wants to change the positions of the elements in the original array, which is not intended by the view function. You can see exceptions of the javascript engine for each array, to be sorted and which has more than one entries. Need to switch the log level of couchdb to "debug" before.
Using the spread operator to create a new array solved the problem:
emit([...doc.tags].sort(), doc._id);

Filter/Search JavaScript array of objects based on other array in Node JS

i have one array of ids and one JavaScript objects array. I need to filter/search the JavaScript objects array with the values in the array in Node JS.
For example
var id = [1,2,3];
var fullData = [
{id:1, name: "test1"}
,{id:2, name: "test2"}
,{id:3, name: "test3"}
,{id:4, name: "test4"}
,{id:5, name: "test5"}
];
Using the above data, as a result i need to have :
var result = [
{id:1, name: "test1"}
,{id:2, name: "test2"}
,{id:3, name: "test3"}
];
I know i can loop through both and check for matching ids. But is this the only way to do it or there is more simple and resource friendly solution.
The amount of data which will be compared is about 30-40k rows.
This will do the trick, using Array.prototype.filter:
var result = fullData.filter(function(item){ // Filter fulldata on...
return id.indexOf(item.id) !== -1; // Whether or not the current item's `id`
}); // is found in the `id` array.
Please note that this filter function is not available on IE 8 or lower, but the MDN has a polyfill available.
As long as you're starting with an unsorted Array of all possible Objects, there's no way around iterating through it. #Cerbrus' answer is one good way of doing this, with Array.prototype.filter, but you could also use loops.
But do you really need to start with an unsorted Array of all possible Objects?
For example, is it possible to filter these objects out before they ever get into the Array? Maybe you could apply your test when you're first building the Array, so that objects which fail the test never even become part of it. That would be more resource-friendly, and if it makes sense for your particular app, then it might even be simpler.
function insertItemIfPass(theArray, theItem, theTest) {
if (theTest(theItem)) {
theArray.push(theItem);
}
}
// Insert your items by using insertItemIfPass
var i;
for (i = 0; i < theArray.length; i += 1) {
doSomething(theArray[i]);
}
Alternatively, could you use a data structure that keeps track of whether an object passes the test? The simplest way to do this, if you absolutely must use an Array, would be to also keep an index to it. When you add your objects to the Array, you apply the test: if an object passes, then its position in the Array gets put into the index. Then, when you need to get objects out of the Array, you can consult the index: that way, you don't waste time going through the Array when you don't need to touch most of the objects in the first place. If you have several different tests, then you could keep several different indexes, one for each test. This takes a little more memory, but it can save a lot of time.
function insertItem(theArray, theItem, theTest, theIndex) {
theArray.push(theItem);
if (theTest(theItem)) {
theIndex.push(theArray.length - 1);
}
}
// Insert your items using insertItem, which also builds the index
var i;
for (i = 0; i < theIndex.length; i += 1) {
doSomething(theArray[theIndex[i]]);
}
Could you sort the Array so that the test can short-circuit? Imagine a setup where you've got your array set up so that everything which passes the test comes first. That way, as soon as you hit your first item that fails, you know that all of the remaining items will fail. Then you can stop your loop right away, since you know there aren't any more "good" items.
// Insert your items, keeping items which pass theTest before items which don't
var i = 0;
while (i < theArray.length) {
if (!theTest(theArray[i])) {
break;
}
doSomething(theArray[i]);
i += 1;
}
The bottom line is that this isn't so much a language question as an algorithms question. It doesn't sound like your current data structure -an unsorted Array of all possible items- is well-suited for your particular problem. Depending on what else the application needs to do, it might make more sense to use another data structure entirely, or to augment the existing structure with indexes. Either way, if it's planned carefully, will save you some time.

A reliable way of sorting an array and passing that information to a view

I am using expressjs to render my routes and pass on database information.
I have two arrays 1. paintingJobs 2. customerList . The (1) paintingJobs array has a foreign key, which contains the customer ID.I want to create an array of customers who currently HAVE painting jobs and pass that array onto the view. To filter the (2)customerList array down to a list of only those customers who currently have painting jobs; I use a series of nested for loops like so.....
for(var i=0; i<paintingJobs.length; i++) {
for(j=0; j<customerList.length; j++) {
if (customerList[j].ID == paintingJobs[i].CustomerID) {
customerRecords.push(customerList[j]);
}
}
}
Creating the new filtered array of customerRecords, which is then passed to the view.
My Question is: If I sort the (1)paintingJobs array by date prior to using it as a filter for my (1)customerList, will the resulting array (customerRecords) be sorted by date as well or more specifically is this a reliable method? If not, would appending the date to the customerList and then sorting the final array be the next best solution?
I am passing this information to my view and then creating an Unordered List based on the number of records.
Thank you for your time and any suggestions
Your double-loop preserves the order of paintingJobs in customerRecords, though unless you have duplicate customerList ID's, looks somewhat inefficient (why no break?).
This means changes to the order of paintingJobs before your double loop will be reflected in customerRecords. Changes after will not.
paintingJobs.sort(however);
for(var i=0; i<paintingJobs.length; i++) {
for(j=0; j<customerList.length; j++) {
if (customerList[j].ID == paintingJobs[i].CustomerID) {
customerRecords.push(customerList[j]);
break; // next paintingJob
}
}
}
It looks like the items in customerList are Objects, so if you make a change to an Object in customerList, this change will also appear in customerRecords even after your double loop.
This is not a answer to your original question, but concerning performance i would create something like a test- object with the ID as key,like
for(var i=0; i<paintingJobs.length; i++) {
testArray[paintingJobs[i].ID] += 1;
}
for(j=0; j<customerList.length; j++) {
testArray[customerList[j].ID] += 1;
}
and check where the testObject has the value 2.
Then with these keys run your operations.
This method will be MUCH faster as your nested loop.

make one array of multiple arrays in javascript with mongodb

i have this structure in my mongodb
{
category:['A','B'],
info:.....,
}
{
category:['A','F','T'],
info:.....,
}
{
category:['A','C'],
info:.....,
}
{
category:['D','B'],
info:.....,
}
i have to query all categories,
var db = mongo.db(read+"#127.0.0.1:27017/database",{safe:false});
db.collection('comercio').find({},{_id:0,'category.$':1},function(err, result_array)
first question, there is any way to get all categories?? an other aproach instead of mine??
second question....
i have to make an array that contains all categories but not repeat any category... in this example i have to make an array that contains this...
all_categories=['A','B','C','D','F','T'];
thank you all again...
You must use Aggregation framework for this query, like this:
db.comercio.aggregate(
{ $unwind : "$category" }
);
After unwind you can use other aggregations (e.g. group) to get what you need.
You don't need aggregation framework to get back an array of distinct categories.
Just use distinct:
> db.comercio.distinct("category");
["A","B","C","D","F","T"]

Parsing a JSON feed from YQL using jQuery

I am using YQL's query.multi to grab multiple feeds so I can parse a single JSON feed with jQuery and reduce the number of connections I'm making. In order to parse a single feed, I need to be able to check the type of result (photo, item, entry, etc) so I can pull out items in specific ways. Because of the way the items are nested within the JSON feed, I'm not sure the best way to loop through the results and check the type and then loop through the items to display them.
Here is a YQL (http://developer.yahoo.com/yql/console/) query.multi example and you can see three different result types (entry, photo, and item) and then the items nested within them:
select * from query.multi where queries=
"select * from twitter.user.timeline where id='twitter';
select * from flickr.photos.search where has_geo='true' and text='san francisco';
select * from delicious.feeds.popular"
or here is the JSON feed itself:
http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20query.multi%20where%20queries%3D%22select%20*%20from%20flickr.photos.search%20where%20user_id%3D'23433895%40N00'%3Bselect%20*%20from%20delicious.feeds%20where%20username%3D'keith.muth'%3Bselect%20*%20from%20twitter.user.timeline%20where%20id%3D'keithmuth'%22&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=
I am using jQuery's $.getJSON method
You don't need to parse JSON by hand. That's the point of JSON. Use JSON.parse(yourJSONstring) to convert it into a Javascript object.
Edit: Actually I'm not sure the browser support for that one. Here's the jQuery way:
http://api.jquery.com/jQuery.parseJSON/
Edit2:
var results = feedObj.query.results.results
for (var i = 0; i < results.length; i++) {
if (results[i].photo) {
// do something with photos
} else if (results[i].item) {
// do something with items
} else {
// do something with entry
}
}
Test for the existence of the results[i].photo object. If it exists, the result is an array which you can loop through and do something with.

Categories

Resources