What's wrong with this while loop? - javascript

I have a function that filters through documents in mongoDB collection and returns all results that has a date that matches a Friday, Saturday or Sunday. This behaves as expected. However, now I need to match those results to determine if they fall on the weekend coming, however my while loop is only returning one result when it should return three. What is going wrong?
//FIND ALL ENTRIES THAT FALL ON A WEEKEND
function weekendPlans(callback) {
Entry.aggregate(
[
{ "$redact": {
"$cond": {
"if": {
"$or": [
{ "$eq": [ { "$dayOfWeek": "$selectedDate" }, 1 ] },
{ "$eq": [ { "$dayOfWeek": "$selectedDate" }, 6 ] },
{ "$eq": [ { "$dayOfWeek": "$selectedDate" }, 7 ] }
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
],
// GET THE RESULTS AND RETURN IF selectedDate MATCHES THIS WEEKEND
function(err,results) {
var i = results.length;
var theWeekend;
console.log(results)
// EVERYTHING WORKS UNTIL HERE
while(i--) {
if(results[i].selectedDate === friday || saturday || sunday) {
theWeekend = results[i];
//console.log(theWeekend);
break;
}
}
callback(err, theWeekend)
}
)};
Expected result:
[ { _id: 56fffb6ceb76276c8f39e3f4,
url: 'http://wellnessmama.com/13700/benefits-coconut-oil-pets/',
title: 'Benefits of Coconut Oil for Pets - Wellness Mama',
selectedDate: Sat Apr 02 2016 01:00:00 GMT+0100 (BST),
__v: 0 },
{ _id: 56fffb8eeb76276c8f39e3f5,
url: 'https://news.ycombinator.com/item?id=11404770',
title: 'The Trouble with CloudFlare | Hacker News',
selectedDate: Sun Apr 03 2016 01:00:00 GMT+0100 (BST),
__v: 0 },
{ _id: 56fffb5ceb76276c8f39e3f3,
url: 'http://londonist.com/2015/11/where-to-eat-and-drink-in-balham',
title: 'Where To Eat And Drink In... Balham | Londonist',
selectedDate: Fri Apr 01 2016 01:00:00 GMT+0100 (BST),
__v: 0 } ]
Current result:
{ _id: 56fffb5ceb76276c8f39e3f3,
url: 'http://londonist.com/2015/11/where-to-eat-and-drink-in-balham',
title: 'Where To Eat And Drink In... Balham | Londonist',
selectedDate: Fri Apr 01 2016 01:00:00 GMT+0100 (BST),
__v: 0 }

Change
results[i].selectedDate === friday || saturday || sunday
to
~results[i].selectedDate.indexOf('Fri') ||
~results[i].selectedDate.indexOf('Sat') ||
~results[i].selectedDate.indexOf('Sun')
because you need to check every variable with a value and if the day string is in the date string.

Related

Newest date in dictionary using Javascript

Having an array of dictionaries I'd like to obtain the most updated record. For instance, consider the following record:
var myArray = [{
itemA: {
name: "Joe Blow",
date: "Mon Jan 31 2016 00:00:00 GMT-0700 (PDT)"
},
itemB: {
name: "Sam Snead",
date: "Sun March 30 2016 00:00:00 GMT-0700 (PDT)"
},
itemC: {
name: "John Smith",
date: "Sat Apr 29 2016 00:00:00 GMT-0700 (PDT)"
}}];
which then I would need to get the most updated record first:
myArray.sort((d1, d2) => new Date(d2.date).getTime() - new Date(d1.date).getTime());
However, I am not getting the correct result. Would you know how to get it working?
Thanks :)
I have refactored your code a little bit.
first of all, your myArray contains only one object. you cannot sort an object like that. therefore I change the structure of your array.
here is a working example:
var myArray = [
{
id: 1,
name: "Sam Snead",
date: "Sun March 30 2016 00:00:00 GMT-0700 (PDT)"
},
{
id: 2,
name: "Joe Blow",
date: "Mon Jan 31 2016 00:00:00 GMT-0700 (PDT)"
},
{
id: 3,
name: "John Smith",
date: "Sat Apr 29 2016 00:00:00 GMT-0700 (PDT)"
}
];
myArray.sort((d1, d2) => new Date(d2.date).getTime() - new Date(d1.date).getTime());
console.log(myArray)
This snippet should help you:
const myArray = [
{
itemA: {
name: "Joe Blow",
date: "Mon Jan 31 2016 00:00:00 GMT-0700 (PDT)"
},
itemC: {
name: "John Smith",
date: "Sat Apr 29 2016 00:00:00 GMT-0700 (PDT)"
},
itemB: {
name: "Sam Snead",
date: "Sun March 30 2016 00:00:00 GMT-0700 (PDT)"
}
}
];
const sortedArray = myArray.map(entry => {
let tmpObj = {};
let tmpSorted = Object.keys(entry).sort((prev, next) => {
return Date.parse(entry[next]?.date) - Date.parse(entry[prev]?.date);
});
tmpSorted.forEach(e => {
tmpObj[e] = entry[e];
})
return tmpObj;
});
console.log(sortedArray);
Your current approach attempts to sort an array of length 1, and the item in the array is an object that represents each record as a property (another object). This makes it a bit inefficient to iterate over your data. Do you need the ItemA labeling for each record and, if so, why not make this part of the object describing the record itself along with date and name?
You can look at Object.entries(), Object.keys(), or Object.values() for ways to make use of object data in an array in order to sort or map over your data.
Assuming your current schema and assuming you had an array with many such objects, if you wanted to find the most recent record in the list for some item i in your array, here is a solution.
You can create a sorted array of objects representing each record for the array item in question. Once sorted, you can take the first or last record to get the oldest or newest. See example below.
const myArray = [
{
itemA: {
name: "Joe Blow",
date: "Mon Jan 31 2016 00:00:00 GMT-0700 (PDT)"
},
itemC: {
name: "John Smith",
date: "Sat Apr 29 2016 00:00:00 GMT-0700 (PDT)"
},
itemB: {
name: "Sam Snead",
date: "Sun March 30 2016 00:00:00 GMT-0700 (PDT)"
}
}
];
const sortedEntries = myArray.map((entry) => {
const records = Object.values(entry);
const sortedRecords = records.sort(function (prev, next) {
return new Date(prev.date) < new Date(next.date) ? -1 : 1;
});
return sortedRecords;
});
// the array with records for each entry now sorted as an array from oldest to most recent date
console.log("sorted entries: ", sortedEntries);
// for example purposes, accessing your array by index, assuming you had more than 1 item in the array
const i = 0;
// get the record with most recent date for this array item
console.log(
"most recent record for example entry is: ",
sortedEntries[i][sortedEntries[i].length - 1]
);
https://codesandbox.io/s/festive-shadow-s36cf3
If you want to find the record with the latest date, you can iterate through the collection and store a record if it satisfies the comparator.
const
identityFn = (x) => x,
findBy = (collection, accessor, comparator) => {
let result, prev, record, i;
if (collection && collection.length) {
for (i = 0; i < collection.length; i++) {
record = collection[i];
if (!prev || comparator(accessor(record), prev)) {
result = record;
prev = accessor(record);
}
};
}
return result;
},
findMax = (collection, accessor = identityFn) =>
findBy(collection, accessor, (curr, prev) => curr > prev);
const
myArray = [{
itemA: { name: "Joe Blow" , date: "Mon Jan 31 2016 00:00:00 GMT-0700 (PDT)" },
itemB: { name: "Sam Snead" , date: "Sun Mar 30 2016 00:00:00 GMT-0700 (PDT)" },
itemC: { name: "John Smith" , date: "Sat Apr 29 2016 00:00:00 GMT-0700 (PDT)" },
itemD: { name: "Jane Doe" , date: null },
itemE: null,
}],
extractDate = (data) => data ? new Date(data?.date) : null,
[key, record] = findMax(
Object.entries(myArray[0]), // Access the entries (key/val pairs)
([key, val]) => extractDate(val) // Map the parsed date
);
console.log(record); // Data for key "itemC"
.as-console-wrapper { top: 0; max-height: 100% !important; }
If you want to sort the records, you can modify the code above like so:
const sortBy = (collection, accessor, comparator) =>
collection.sort((a, b) => comparator(accessor(a), accessor(b)));
const
myArray = [{
itemA: { name: "Joe Blow" , date: "Mon Jan 31 2016 00:00:00 GMT-0700 (PDT)" },
itemB: { name: "Sam Snead" , date: "Sun Mar 30 2016 00:00:00 GMT-0700 (PDT)" },
itemC: { name: "John Smith" , date: "Sat Apr 29 2016 00:00:00 GMT-0700 (PDT)" },
itemD: { name: "Jane Doe" , date: null },
itemE: null,
}],
extractDate = (data) => data ? new Date(data?.date) : null,
sorted = sortBy(
Object.entries(myArray[0]), // Access the entries (key/val pairs)
([key, val]) => extractDate(val), // Map the parsed date
(curr, prev) => prev - curr // Same as (DESC): (curr - prev) * -1
);
console.log(sorted);
.as-console-wrapper { top: 0; max-height: 100% !important; }
Edit
Added null values
Changed ([key, { date }]) => new Date(date) to ([key, val]) => extractDate(val) to handle null values

Group json data array by month

I have been trying to take the json data outputted from the database and create an new array that groups the data by month and year.
The problem is my new array doesn't output in the format that i need so i need to add the month and year but can't get the month grouping to work first. I think that might be right and resolve my issue, but I need help as arrays are confusing.
I have a codepen demo https://codepen.io/james182/pen/yLaqybP
var data = [
{ name: "First", timestampSent: "Wed, 25 Nov 2020 - 11:01 AM" },
{ name: "Second", timestampSent: "Wed, 25 Nov 2020 - 11:21 AM" },
{ name: "Third", timestampSent: "Thu, 26 Nov 2020 - 10:21 AM" },
{ name: "Fourth", timestampSent: "Fri, 27 Nov 2020 - 13:52 PM" },
{ name: "Fifth", timestampSent: "Tue, 24 Dec 2020 - 11:01 AM" },
{ name: "Sixth", timestampSent: "Wed, 25 Dec 2020 - 01:01 AM" }
];
// Clear console before running
console.clear();
var list = [];
for (i = 0; i < data.length; i++) {
var dates = data[i].timestampSent.slice(5, 16);
var mth = data[i].timestampSent.split(" ")[2];
if (!list[mth]) {
list[mth] = [];
}
list[mth].push({ name: data[i].name, date: data[i].timestampSent });
console.log(mth);
}
console.log(JSON.stringify(list));
//console.log('list', list);
/*
outcome:
[{
'Nov': [
{
'name': 'First',
'timestampSent': 'Wed, 25 Nov 2020 - 11:01 AM'
},
{
'name': 'Second',
'timestampSent': 'Wed, 25 Nov 2020 - 11:21 AM'
},
{
'name': 'Third',
'timestampSent': 'Thu, 26 Nov 2020 - 10:21 AM'
},
{
'name': 'Fourth',
'timestampSent': 'Fri, 27 Nov 2020 - 13:52 PM'
}
],
'Dec': [
{
'name': 'Fifth',
'timestampSent': 'Tue, 24 Dec 2020 - 11:01 AM'
},
{
'name': 'Sixth',
'timestampSent': 'Wed, 25 Dec 2020 - 01:01 AM'
}
]
}]
*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Your list should not be an array. Since you are using the month name ('Nov', 'Dec') as keys you should use an object.
var list = {};
try change the line
list = []
to
list = {}
You will be using an object, not a list.
Try it here

Converting a firebase snapshot to array recursively not working correctly

I have the following structure on my firebase database:
I need to get an array of all the data with a special structure. This is how I do it:
const isObject = obj => {
return Object.prototype.toString.call(obj) === '[object Object]' ? true : false;
};
function snapshotToArray(snapshot) {
var returnArr = [];
snapshot.forEach(function(childSnapshot) {
var item = childSnapshot.val();
item.key = childSnapshot.key;
returnArr.push(item);
if (isObject(item)){
returnArr = returnArr.concat(snapshotToArray(childSnapshot));
}
});
return returnArr;
};
And call it:
snapshotToArray(snapshot); // 'snapshot' is the data from database in a snapshot format
Getting:
[ { 'Diciembre-2018': { '-LJV5UxepDNSR5yUCDbf': [Object] },
'Julio-2018': { '-LJUt8yTjpK3oq2wRd_g': [Object] },
key: '2018' },
{ '-LJV5UxepDNSR5yUCDbf':
{ pin: 'mi-pin-dic',
timestamp: 'Thu Aug 09 2018 13:11:39 GMT-0600 (GMT-06:00)' },
key: 'Diciembre-2018' },
{ pin: 'mi-pin-dic',
timestamp: 'Thu Aug 09 2018 13:11:39 GMT-0600 (GMT-06:00)',
key: '-LJV5UxepDNSR5yUCDbf' },
'mi-pin-dic',
'Thu Aug 09 2018 13:11:39 GMT-0600 (GMT-06:00)',
{ '-LJUt8yTjpK3oq2wRd_g':
{ pin: 'mi-pin-julio',
timestamp: 'Thu Aug 09 2018 12:13:21 GMT-0600 (GMT-06:00)' },
key: 'Julio-2018' },
{ pin: 'mi-pin-julio',
timestamp: 'Thu Aug 09 2018 12:13:21 GMT-0600 (GMT-06:00)',
key: '-LJUt8yTjpK3oq2wRd_g' },
'mi-pin-julio',
'Thu Aug 09 2018 12:13:21 GMT-0600 (GMT-06:00)' ]
But as you can see, in the 3rd and 5th iteration it gets an extra data:
'mi-pin-dic',
'Thu Aug 09 2018 13:11:39 GMT-0600 (GMT-06:00)',
'mi-pin-julio',
'Thu Aug 09 2018 12:13:21 GMT-0600 (GMT-06:00)'
My question:
How can I avoid this issue? Any ideas?

while loop and callback return different results

I have a while loop that matches a condition to filter data from mongodb. However, when I use the callback I only receive one result to the console.log. If I console.log inside the while loop, I should receive three entries. Why is only one piece of data making it to the callback?
while(i--) {
if (0 >= [friday, saturday, sunday].indexOf(results[i].selectedDate)) {
theWeekend = results[i];
console.log(theWeekend); //returns three results (correct)
}
}
callback(err, theWeekend)
console.log(theWeekend); //returns one results (incorrect)
Correct data
{ _id: 56fffb5ceb76276c8f39e3f3,
url: 'http://londonist.com/2015/11/where-to-eat-and-drink-in-balham',
title: 'Where To Eat And Drink In... Balham | Londonist',
selectedDate: Fri Apr 01 2016 01:00:00 GMT+0100 (BST),
__v: 0 }
{ _id: 56fffb8eeb76276c8f39e3f5,
url: 'https://news.ycombinator.com/item?id=11404770',
title: 'The Trouble with CloudFlare | Hacker News',
selectedDate: Sun Apr 03 2016 01:00:00 GMT+0100 (BST),
__v: 0 }
{ _id: 56fffb6ceb76276c8f39e3f4,
url: 'http://wellnessmama.com/13700/benefits-coconut-oil-pets/',
title: 'Benefits of Coconut Oil for Pets - Wellness Mama',
selectedDate: Sat Apr 02 2016 01:00:00 GMT+0100 (BST),
__v: 0 }
Incorrect data
{ _id: 56fffb6ceb76276c8f39e3f4,
url: 'http://wellnessmama.com/13700/benefits-coconut-oil-pets/',
title: 'Benefits of Coconut Oil for Pets - Wellness Mama',
selectedDate: Sat Apr 02 2016 01:00:00 GMT+0100 (BST),
__v: 0 }
You need to use an array to store all the results as follows:
var theWeekends = []
while(i--) {
if (0 >= [friday, saturday, sunday].indexOf(results[i].selectedDate)) {
theWeekends.push(results[i]);
}
}
callback(err, theWeekends)
console.log(theWeekends); //returns 3 results (correct)

Amend results from two collections into an array using _.each()

My goal:
Call an API and inside this API I would like to:
Find Bills
Find all transactions under each bill (by billId)
Return the values in a JSON ARRAY
The bill array look like this:
{ _id: 549bf0597886c3763e000001,
billName: 'Leasing',
startDate: Thu Dec 25 2014 01:00:00 GMT+0100 (CET),
endDate: Sun Oct 15 2017 00:00:00 GMT+0200 (CEST),
amount: 16500,
type: 4,
timestamp: Thu Dec 25 2014 12:09:13 GMT+0100 (CET),
__v: 0 },
{ _id: 54a014bfac01ca3526000001,
billName: 'Test',
startDate: Tue Oct 28 2014 01:00:00 GMT+0100 (CET),
endDate: Wed Dec 20 2017 00:00:00 GMT+0100 (CET),
amount: 1000,
type: 4,
timestamp: Sun Dec 28 2014 15:33:35 GMT+0100 (CET),
__v: 0 }
From this array, which I get in the step 1, I would like to query the transactions collections and get each transaction for each bill.
The array would have the following transformation:
From:
{ _id: 549bf0597886c3763e000001,
billName: 'Leasing',
startDate: Thu Dec 25 2014 01:00:00 GMT+0100 (CET),
endDate: Sun Oct 15 2017 00:00:00 GMT+0200 (CEST),
amount: 16500,
type: 4,
timestamp: Thu Dec 25 2014 12:09:13 GMT+0100 (CET),
__v: 0 },
{ _id: 54a014bfac01ca3526000001,
billName: 'Test',
startDate: Tue Oct 28 2014 01:00:00 GMT+0100 (CET),
endDate: Wed Dec 20 2017 00:00:00 GMT+0100 (CET),
amount: 1000,
type: 4,
timestamp: Sun Dec 28 2014 15:33:35 GMT+0100 (CET),
__v: 0 }
To:
{ _id: 549bf0597886c3763e000001,
billName: 'Leasing',
startDate: Thu Dec 25 2014 01:00:00 GMT+0100 (CET),
endDate: Sun Oct 15 2017 00:00:00 GMT+0200 (CEST),
amount: 16500,
type: 4,
timestamp: Thu Dec 25 2014 12:09:13 GMT+0100 (CET),
__v: 0 ,
transactions: {
{
"_id" : ObjectId("549ea8c957b654ef64000003"),
"billId" : "5499aece1d7be6c6a3000001",
"paymentDate" : ISODate("2014-12-27T12:40:41.311+0000"),
"amount" : NumberInt(2400),
"timestamp" : ISODate("2014-12-27T12:40:41.311+0000"),
"__v" : NumberInt(0)
}
{
"_id" : ObjectId("549ea9446163b3c666000001"),
"billId" : "5499aece1d7be6c6a3000001",
"paymentDate" : ISODate("2014-12-27T12:42:44.975+0000"),
"amount" : NumberInt(2400),
"timestamp" : ISODate("2014-12-27T12:42:44.975+0000"),
"__v" : NumberInt(0)
}
}
},
{ _id: 54a014bfac01ca3526000001,
billName: 'Test',
startDate: Tue Oct 28 2014 01:00:00 GMT+0100 (CET),
endDate: Wed Dec 20 2017 00:00:00 GMT+0100 (CET),
amount: 1000,
type: 4,
timestamp: Sun Dec 28 2014 15:33:35 GMT+0100 (CET),
__v: 0 }
In my attempt, Im succeding until I get the bills ID from the bill collection but I cannot succeed to get the transaction IDs into an array.
My attempt looks like this:
app.get('/getbills', function(req,res) {
function getTransactions(item, key){
var billId = item._id;
Transactions.find({billId : billId}, function(err, transactions){ // TODO: Needs to look for transactions inside the date.
if (err)
console.log('error: '+ err)
else if (transactions.length !== 0){
return transactions;
}
});
};
Bills.find({type: bill_type}).find(function(err, bills){
if(err)
res.send(err);
details.bills = bills;
details.bills.transations = _.each(bills, getTransactions);
res.send(details);
});
});
I'm using _.each to hold the billId and query the transactions table but there are not enough examples explaining how to use this function in the way I'm trying. Or maybe my attempt is wrong.
Any help is welcome.
Thanks in advance.
You are not waiting for you second call to finish, so you don't have all data at hand. Your return statement does not work as you think it will.
You should read a bit about asynchronicity in JavaScript :)
This code should work. Please take some time to study it and understand why. The trySend function acts as a simple synchronizer and only responds when all data is available. This is not the best way to do it - only the simplest.
app.get('/bills', function( req, res ) {
Bills.find({type: bill_type}, function( err, bills ) {
if( err ) return res.send(err);
var tries = 0;
var details = { bills: bills };
var trySend = function (){
tries++;
if (tries === bills.length) {
res.send(details);
}
};
bills.forEach( function ( bill ) {
Transactions.find({billId : bill._id}, function ( err, transactions ) {
if ( err ) return res.send( err );
bill.transations = transactions;
trySend();
});
});
});
});

Categories

Resources