I'm working through gathering information from multiple arrays but I've hit a stumbling block. I need to be able to determine how many days were spent in each city. The trouble is I can't figure out a way to count time entries that span a single day as 1 day. In the below the first two San Diego entries should result in a single day since both logs happened within the same day.
timeLogs = [
{'city':'San Diego','date':'2017-03-21T18:52:00.984Z'},
{'city':'San Diego','date':'2017-03-21T12:13:00.984Z'},
{'city':'San Diego','date':'2017-03-19T11:02:00.984Z'},
{'city':'Boulder','date':'2017-02-12T11:29:00.984Z'}
]
What I'm after is the following resulting array based on the above:
daysPerCity = [
{'San Diego':'2'},
{'Boulder':'1'}
]
Currently I'm working on a loop which coverts the dates to strings and then checks for equality, if the same I'm trying to not increment the city in the new array but I'm stuck when it hits the very first instance of a city...
You can use Array methods like reduce and map to build an object containing unique days grouped by city, and then use Object.keys(...).length to get the number of distinct days.
var timeLogs = [
{ city: 'San Diego', date: '2017-03-21T18:52:00.984Z' },
{ city: 'San Diego', date: '2017-03-21T12:13:00.984Z' },
{ city: 'San Diego', date: '2017-03-19T11:02:00.984Z' },
{ city: 'Boulder', date: '2017-02-12T11:29:00.984Z' }
]
var daysPerCity = timeLogs.reduce(function (map, e) {
(map[e.city] = map[e.city] || {})[e.date.slice(0, 10)] = true
return map
}, {})
Object.keys(daysPerCity).forEach(function (k) {
this[k] = Object.keys(this[k]).length
}, daysPerCity)
console.log(daysPerCity)
You could use this ES6 code:
const timeLogs = [
{'city':'San Diego','date':'2017-03-21T18:52:00.984Z'},
{'city':'San Diego','date':'2017-03-21T12:13:00.984Z'},
{'city':'San Diego','date':'2017-03-19T11:02:00.984Z'},
{'city':'Boulder','date':'2017-02-12T11:29:00.984Z'}
];
const result = Object.assign({}, ...Array.from(
timeLogs.reduce( (acc, {city, date}) => {
(acc.get(city) || acc.set(city, new Set).get(city))
.add(date.substr(0, 10));
return acc;
}, new Map),
([city, days]) => ({ [city]: days.size })
));
console.log(result);
Related
I have been struggling in comparing two different array lists. I need quick solution. It's really haywire to me.
What my scenario is, I wanna remove selected values, if record is not exist in another document or if exist than skip that record only and remove other records.
I made a list of objectIds input by user, when user checked the checkboxes, I am getting that id and storing in an array and making a list as given below:
"id": ["62ff99e4306e722e7201657a",
"62ffb71d2a809d528067eeca",
"62f7ce478ac4537516bdec04",
"62cb1660b851d8bb6af08aa7",
"62cb1770b851d8bb6af08ad8",]
And comparing the above array with the below document brand field:
[
{
brand: [
new ObjectId("62c95cae5db50418e6281916"),
new ObjectId("62cb1660b851d8bb6af08aa7"),
new ObjectId("62cb1770b851d8bb6af08ad8")
]
},
{
brand: [
new ObjectId("62c95cae5db50418e6281916"),
new ObjectId("62cb1660b851d8bb6af08aa7"),
new ObjectId("62cb1770b851d8bb6af08ad8")
]
},
{
brand: [
new ObjectId("62c95cae5db50418e6281916"),
new ObjectId("62cb1660b851d8bb6af08aa7"),
new ObjectId("62cb1770b851d8bb6af08ad8")
]
}
]
Even if you see the second document which I am getting from mongodb has brand field which has duplicate records.
At the end what output I require is, when I click delete all button it has to delete total 3 records except below records which are matching in both arrays:
["62cb1660b851d8bb6af08aa7", "62cb1770b851d8bb6af08ad8"]
Would really appreciate if anyone solve my this issue.
I achieved opposite solution based on my question and response of #im2wddrf. Have a loook on the opposite solution.
const listCatalog = await Catalog.aggregate([
{ $project: { _id: 0, brand: 1 } }, { $unwind: "$brand" },
]);
const checkCatalog = listCatalog.map(val => {
return val.brand.toString()
});
const uniqueCatalog = _id.filter(val => {
return checkCatalog.indexOf(val) === -1
});
console.log(uniqueCatalog, "uniqueCatalog")
Here is my proposed solution:
convert your first array (let's call it asset1) to a flat array.
Then take your second array (let's call it asset2), and convert that to a flat array of arrays (no objects).
Use reduce to compare the two and keep only the common ID's that can be found.
const asset1 = {
"id": [
"62ff99e4306e722e7201657a",
"62ffb71d2a809d528067eeca",
"62f7ce478ac4537516bdec04",
"62cb1660b851d8bb6af08aa7",
"62cb1770b851d8bb6af08ad8",
]
}
const asset2 = [
{
brand: [
new ObjectId("62c95cae5db50418e6281916"),
new ObjectId("62cb1660b851d8bb6af08aa7"),
new ObjectId("62cb1770b851d8bb6af08ad8")
]
},
{
brand: [
new ObjectId("62c95cae5db50418e6281916"),
new ObjectId("62cb1660b851d8bb6af08aa7"),
new ObjectId("62cb1770b851d8bb6af08ad8")
]
},
{
brand: [
new ObjectId("62c95cae5db50418e6281916"),
new ObjectId("62cb1660b851d8bb6af08aa7"),
new ObjectId("62cb1770b851d8bb6af08ad8")
]
}
];
// step 1: I would convert asset1 to a simple, flat array
const mod1 = [ ...asset1.id ]
// step 2: I would convert asset2 to an array of arrays, no objects
const mod2 = asset2.map(i => {
return [ ...i.brand.map(b => b.toString()) ]
});
// now use reduce to extract only the common id's between mod1 and mod2
const result = mod2.reduce((accum, curr) => {
return accum.filter(a => curr.includes(a));
}, mod1)
console.log(mod1);
console.log(mod2);
console.log(result);
It works except when the subject unless the subject is the same name. Then I get the first date to the second subject that is the same.
I can't change the array since it's through API. However can I make so somehow if the first date is already set on math, then it should add the second date to second subject? Now the second subject get's the first date
var subjects = [
{ name: "math" }, //The first
{ name: "sports" },
{ name: "math" }, //The second
{ name: "art" },
];
var subjectdates = [
{ name: "math", year: 2017 }, //first date
{ name: "sports", year: 2018 },
{ name: "math", year: 2019 }, //second date
{ name: "art", year: 2020 },
];
const addDates = subjects.map((classes) => ({
subject: classes,
end_subject_date: subjectdates.find((item) => classes.name == item.name),
}));
console.log(addDates);
Using Array#reduce on subjectdates, construct a Map where the key is the name and the value is a list of the elements of this name.
Then, in the loop, to get the end_subject_date, you can use Map#get to get the list of elements of this name, and Array#shift to get and remove the first element:
const
subjects = [ {name:"math"}, {name:"sports"}, {name:"math"}, {name:"art"} ],
subjectdates = [ {name:"math",year:2017}, {name:"sports",year:2018}, {name:"math",year:2019}, {name:"art",year:2020} ];
const subjectDatesMap = subjectdates.reduce((map, item) =>
map.set(
item.name,
[...(map.get(item.name) || []), item]
)
, new Map);
const addDates = subjects.map(classes => ({
subject: classes,
end_subject_date: (subjectDatesMap.get(classes.name) || []).shift()
}));
console.log(addDates);
If you have the same keys in arrays:
Sort array by keys:
subjects = subjects.sort((a,b)=>a.name>b.name?1:-1);
subjectdates = subjectdates.sort((a,b)=>a.name>b.name?1:-1);
Insert values by index:
const result = subjects.map((s, i)=>
({ subject:s.name, end_subject_date:subjectdates[i].year}) );
I'm trying to get the key of these json objects in order to create a new object with extra filed to create table headers in a React app. JSON data:
let example = [
{
id: 1,
city: 'New York',
},
{
id: 2,
city: 'Paris',
},
]
The function:
getKeys() {
return example.map((key) => {
return {
cityName: key, // gets the whole array
capital: false,
};
});
}
I tries Object.keys( example);, it returns integers; 0, 1.
How can I get the keys in this case? Thanks.
You are trying to map the keys for an array since example is an array. If the data are consistent throughout the array get the first element example[0] and do Object.keys().
So Object.keys(example[0])
There's no need to get the keys if you just want to add a property to the items in the array. I think there's a misunderstanding about .map, which gives you a single item/object in the array, not the keys.
Something like this perhaps?
let example = [{
id: 1,
city: 'New York',
}, {
id: 2,
city: 'Paris',
}];
const modifiedArray = function(arr) {
return arr.map(item => {
return {
id: item.id,
cityName: item.city,
capital: false,
};
})
}
const newArray = modifiedArray (example);
console.log(newArray )
I spent more time on this than I would like to admit. I have trouble constructing an object filled with an array.
I would like my data to look like this:
items={
{
'2012-05-22': [{text: 'item 1 - any js object'}],
'2012-05-23': [{text: 'item 2 - any js object'}],
'2012-05-24': [],
'2012-05-25': [{text: 'item 3 - any js object'},{text: 'any js object'}],
}
}
I am making a database call and the data I receive looks like this:
Object {start: "08:00:00", end: "09:00:00", full_name: "Tomomi", date: "2017-06-08", Barber_id: "1"…}
The data I am interested in is the full_name value and the date value.
This is what I have attempted:
let newItems = {};
axios.post(endpoint, {lookup: day.dateString}).then((customerData) => {
customerData.data.forEach((val,key)=>{
newItems = {[val.date]:[]};
newItems[val.date].push({name:val.full_name});
console.log(newItems);
})
}
It looks like this:
Object {2017-06-08: Array(1)}
2017-06-08
:
Array(1)
This is very close, but the problem is that my code is overwriting my data.
I am trying to create this dynamically:
'2012-05-25': [{text: 'item 3 - any js object'},{text: 'any js object'}],
So that each date can have many users. Hopefully, this makes sense.
Thanks for any help.
The function expression you pass to forEach has this as the first line:
newItems = {[val.date]:[]};
This resets the newItems object to an object with one date:name pair. You really want something more like:
newItems[val.date]?newItems[val.date].push({name:val.full_name}):newItems[val.date]=[];
var byDate = {}; // Object to store received data by-date
function addIntoByDate( obj ) {
byDate[obj.date] = byDate[obj.date] || [];
byDate[obj.date].push( obj );
}
// Simulate adding server data one by one
addIntoByDate( {date: "2017-06-08", full_name: "Cat", text:"Foo!!"} ); // < SAME DATE
addIntoByDate( {date: "2016-05-23", full_name: "Dog", text:"Bar"} );
addIntoByDate( {date: "2017-06-08", full_name: "Bug", text:"Baz..."} ); // < SAME DATE
// test
console.dir(byDate);
You can use object destructuring, computed property and Object.assign()
const newItems = {};
const data = [
{
start: "08:00:00"
, end: "09:00:00"
, full_name: "Tomomi"
, date: "2017-06-08"
, Barber_id: "1"
}
];
data.forEach(({date, full_name}) =>
Object.assign(newItems, {[date]: [{/* text: */ full_name}]}));
console.log(newItems);
I need help with something that might be a common problem and something that others would benefit from as well, which is to modify dates in an object and combine them into a chronological list. The overall goal is to create a list which reflects all of the upcoming special dates in a year:
1 Jan - Sharpe's Anniversary
2 May - Edward's Birthday
12 Dec - Zero's Anniversary
etc...
I began by creating an object to represent this. Then slice out the year so that a comparison won't just arrange them by their order of initial occurrence, but will give an annual basis. Then perform a comparison to arrange the dates in chronological order. Then log out the result with the matching person's identity.
Up to this point I got it to work. However, I do not know how to repeat this and make it DRY. Certainly it would be sloppy to run this for anniversaries, then for birthdays without making some sort of custom function. All my attempts have not ended successfully.
Does anyone have a more elegant solution?
Much thanks to the community here :)
// Sample data
var items = [{
name: 'Edward',
anniversary: "2015-01-23",
birthday: "1988-05-02"
},
{
name: 'Sharpe',
anniversary: "2017-01-01",
birthday: "1988-05-10"
},
{
name: 'And',
anniversary: "2018-05-10",
birthday: "1988-06-12"
},
{
name: 'The',
anniversary: "1988-08-11",
birthday: "1979-03-12"
},
{
name: 'Magnetic',
anniversary: "2017-01-05",
birthday: "1956-06-21"
},
{
name: 'Zeros',
anniversary: "1990-12-12",
birthday: "1935-07-23"
}
];
// Slice out the year so that dates are annualized
for (var i = 0; i < items.length; i++) {
items[i].anniversary = items[i].anniversary.slice(5, 10);
};
// Sort dates in chronological order
items.sort(function(a, b) {
return new Date(a.anniversary) - new Date(b.anniversary);
});
// Console.log the dates with their associated name
for (var i = 0; i < items.length; i++) {
console.log(items[i].anniversary + " " + items[i].name);
}
When you remove the year from a date like "1988-08-11" you get "08-11". If you then parse this with the built-in Date parser, you'll either get an invalid date, or a date for 1 November 0008, when the original date was for 11 August. The parser will see a year and a month, and use 1 for the missing day.
But don't dispair! The ISO 8601 date format can be sorted as a string, so do as you are and sort as strings, not dates, e.g.
// Sample data
var items = [{
name: 'Edward',
anniversary: "2015-01-23",
birthday: "1988-05-02"
},
{
name: 'Sharpe',
anniversary: "2017-01-01",
birthday: "1988-05-10"
},
{
name: 'And',
anniversary: "2018-05-10",
birthday: "1988-06-12"
},
{
name: 'The',
anniversary: "1988-08-11",
birthday: "1979-03-12"
},
{
name: 'Magnetic',
anniversary: "2017-01-05",
birthday: "1956-06-21"
},
{
name: 'Zeros',
anniversary: "1990-12-12",
birthday: "1935-07-23"
}
];
// Get the events
var specialDates = items.reduce(function(acc, item) {
acc.push([item.name, item.anniversary.substr(5), 'Anniversary'], [item.name, item.birthday.substr(5), 'Birthday']);
return acc;
}, []).sort(function (a, b) { // sort on month
return a[1].localeCompare(b[1]);
}).map(function(event) { // Replace month number with short name
var months = [,'Jan','Feb','Mar','Apr','May','Jun',
'Jul','Aug','Sep','Oct','Nov','Dec'];
return [event[0], months[+event[1].split('-')[0]] + ' ' + event[1].substr(3), event[2]];
});
// Write result
specialDates.forEach(function(event) {
console.log(event[1] + ': ' + event[0] + ' ' + event[2]);
});
This could be a bit smarter and get the event name from the original object so that you can add as many event types as you want and not have them hard coded, so an object like:
var items = [{
name: 'Edward',
events: {
anniversary: "2015-01-23",
birthday: "1988-05-02"
}
},
...
Also note that new Date("2015-01-23") will treat the string as UTC (timezone offset +00:00), so for hosts west of Greenwich the date might appear to be the day before.
let goal = items
.map( ({ name, anniversary }) => ({ name, 'anniversary': anniversary.slice( 5, 10 ) }) )
.sort( ({ 'anniversary': a }, { 'anniversary': b }) => {
if( a > b ) return 1;
if( a < b ) return -1;
return 0;
}
.map( ({ name, anniversary }) => anniversary + ' ' + name );
goal.forEach( item => { console.log( item ); });