MongoDB - finding common value count between a set of documents - javascript

I have the documents in the with the two fields and I want to find common value count between a same set (category) of rows: e.g.
Current data look something like this (assume in Json format):
I need an output like this:
Will be grateful for any guidance/pointers. Thanks

First, get your data in the form of an array of objects. Then, we can use the following algorithm to get what you need:
Get the unique categories ["Music", "Film", "History", "Science"]
Get the combinations of those categories [["Music", "Film"], ["Music", "History"], ["Music", "Science"], ["Film", "History"], ...]
Create a mapping of category name to the books that are contained in that category. We can use a Set to ensure that the values are unique. The map will have the structure like {"Music": Set("A", "B"), "Film": Set("A", "B", "C"), "History": Set("C", "B"), "Science": Set("C")}
Use the objects and arrays that you just created to find the duplicates between the combinations.
When all is said and done, you'll have an array that has the following structure: [ [cat1, cat2, [bookInCommon1, bookInCommon2]], [cat1, cat3, [bookInCommon1, bookInCommon2]], ...]
Run the code below to see it in action. mongoData holds the data that is fetched from Mongo.
const mongoData = [{
category: "Music",
book: "A"
}, {
category: "Music",
book: "B"
},{
category: "Music",
book: "A"
},{
category: "Film",
book: "A"
},{
category: "Film",
book: "A"
},{
category: "Film",
book: "B"
},{
category: "Film",
book: "C"
},{
category: "Film",
book: "C"
},{
category: "Film",
book: "A"
},{
category: "History",
book: "C"
},{
category: "History",
book: "C"
},{
category: "History",
book: "B"
},{
category: "History",
book: "B"
},{
category: "Science",
book: "C"
},{
category: "Science",
book: "C"
},{
category: "Science",
book: "C"
}];
// Step 1: Get the categories
const categories = Array.from(new Set(mongoData.map(x => x.category)));
// Step 2: Get combinations of those categories
const combos = [];
for(let i = 0; i < categories.length - 1; i++) {
let outerCat = categories[i];
for(let j = i + 1; j < categories.length; j++) {
let innerCat = categories[j];
combos.push([
outerCat,
innerCat
]);
}
}
// Step 3: Map the categories to the books that they contain
const catBooks = mongoData.reduce((map, entry) => {
map[entry.category] = map[entry.category] || new Set();
map[entry.category] = map[entry.category].add(entry.book);
return map;
}, {});
// Step 4: Get the duplicate books for each combo
combos.forEach((combo, index) => {
const cat1 = combo[0];
const cat2 = combo[1];
const cat1BooksArr = Array.from(catBooks[cat1]);
const cat2BooksSet = catBooks[cat2];
const dupes = cat1BooksArr.filter(book => {
return cat2BooksSet.has(book);
});
combos[index].push(dupes); // push into combos array
});
// Done! Your combos array contains arrays that look like this: [cat1, cat2, [dupes]]
combos.forEach(combo => {
console.log("Combo: " + combo[0] + ", " + combo[1]);
console.log("\tNumber of dupes: " + combo[2].length);
});

Related

Functional Programming exercise I can't figure out

I've been looking at a problem for hours and failing to find a solution. I'm given an array of customer objects.
In each customer object is an array of friends.
In the array of friends is an object for each friend, containing some data, including a name key/value pair.
What I'm trying to solve for: I'm given this customers array and a customer's name. I need to create a function to find if this customer name is in any other customer's friend lists, and if so, return an array of those customer's names.
Below is a customer list. And as an example, one of the customers is Olga Newton. What the code should be doing is seeing that Olga Newton is a customer and is also in the friends lists of Regina and Jay, and should be returning an array of Regina and Jay.
I thought I could do this simply with a filter function, but because the friends list is an array with more objects, this is adding level of complexity for me I can't figure out.
Below is a customer array. The out put should be
['Regina', 'Jay']
and what I've gotten has either been
[{fullCustomerObj1}, {fullCustomerObj2}]
or
[ ]
What am I missing?
Here is the customer array:
var customers = [{
name: "Olga Newton",
age: 43,
balance: "$3,400",
friends: [{
id: 0,
name: "Justice Lara"
}, {
id: 1,
name: "Duke Patrick"
}, {
id: 2,
name: "Herring Hull"
}, {
id: 3,
name: "Johnnie Berg"
}]
}, {
name: "Regina",
age: 53,
balance: "$4,000",
friends: [{
id: 0,
name: "Cheryl Kent"
}, {
id: 1,
name: "Cynthia Wells"
}, {
id: 2,
name: "Gutierrez Waters"
}, {
id: 3,
name: "Olga Newton"
}]
}, {
name: "Jay",
age: 28,
balance: "$3,000",
friends: [{
id: 0,
name: "Cross Barnett"
}, {
id: 1,
name: "Raquel Haney"
}, {
id: 2,
name: "Olga Newton"
}, {
id: 3,
name: "Shelly Walton"
}]
}];
Use filter and map, please.
function friends(c, name){
return c.filter((a) => {
return a.friends.map(b => b.name).includes(name)
}).map(a => a.name);
}
console.log(friends(customers, "Olga Newton"));
// ['Regina', 'Jay']
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
We look to an array (friends[]) inside anther (customers[]), So used two for loops, the first determine witch customer will look for his friends, and the second the array will search inside, then set if statement if the cust name is inside friends[]: adding the customer name to customerFriends[] array, At the end return the customerFriends[].
let cust = "Olga Newton"; // Get the customer name who you look for his friends.
const findFriend = (cust, arrs) => { // Create findFriend function.
let customerFriends = []; // Create an array to set the result to it.
for (let i = 0; i < arrs.length; i++) { // For each Customer.
for (const arr of arrs[i].friends) { // For each Friend.
if (arr.name === cust) { // Use Strict equality to find Customer name in friends[].
customerFriends.push(arrs[i].name); // Add the customer name to the customerFriends[].
}
}
}
return customerFriends;// Return the final results.
}
console.log(findFriend(cust, customers)); // Call the function.

How to fetch particular data from array of objects and store in new array in js (vue js)

I am having this array of object
let detail : [
0: {
Code: "Code 1"
Price: "0.00"
},
1: {
Code: "Code 2"
Price: "9.00"
}
]
I want to store the price in an array(for eg: result) so that I can merge it with another existing array of the object(for eg: alldetail)
result = [
0: {
Price:"0.00"
},
1: {
Price:"9.00"
},
]
Using map() method which creates a new array filled with the results of the provided function executing on every element in the calling array.
So, in your case, you'll return an object with the key Price and the value will be the current object with the value of it's Price property.
let detail = [
{
Code: "Code 1",
Price: "0.00"
},
{
Code: "Code 2",
Price: "9.00"
}
];
let result = detail.map(current => {return {Price: current.Price}});
console.log(result);
Use map to create a new array of objects.
const detail = [
{ Code: "Code 1", Price: "0.00" },
{ Code: "Code 2", Price: "9.00" }
];
const result = detail.map(({ Price }) => ({ Price }));
console.log(result);
Additional documentation
Destructuring assignment.

How do I save JavaScript variables permenantly/persistently?

I have 5 arrays, which can all be updated by the user. They are structured as:
var nameStore = [
{ name: "Tim Jones", idn: "i0001" },
{ name: "Mark Gooderham", idn: "i0002" }
];
var nameStoreName;
var subjectStore = [
{ name: "Sailing", ids: "s0001" },
{ name: "Navigation", ids: "s0002" }
];
var subjectStoreName;
var classStore = [
{ name: "Class A", idc: "c0001" },
{ name: "Class 2", idc: "c0002" }
];
var classStoreName;
var roomStore = [
{ name: "Room 1", idr: "r0001" },
{ name: "Room 2", idr: "r0002" }
];
var weekStore = [
{ week: 1, weekTimes: ["mon01i0001s0001c0001r0001", "mon02i0001s0002c0002r0002"] },
{ week: 2, weekTimes: ["mon02i0002s0002c0002r0002"] },
];
I want to be able to store these arrays permanently, so when the webpage closes, the arrays will have their data saved, and can then be accessed by another user later. I know this is a big question, but even if you could just direct me to other resources, that would help.
Thanks.
For that purpose, you should store your arrays in a database. Before closing page, submit arrays to DB and update records. When user opens the webpage, query DB and get arrays' contents.
You can use localStorage to store the array on the browser if you're not using database to persist.
localStorage.setItem('key', JSON.stringify(arr));
var item = JSON.parse(localStorage.getItem('key'));

Creating an object from API data and adding it to an array dynamically

I have a data set that I'm pulling in from a database. It's one dimensional and I basically need to make it more structured. I refer to it as "flat".
I need to display a heading, and items under that heading that are related to the heading.
The data comes in as having and section_name (the heading) and item_name (items) and other data unique to each item like download URLs etc.
item_name(item)_______section_name(header)
first_________________Funds
second________________Funds
third_________________Funds
fourth________________Literature
fifth_________________Literature
sixth_________________Literature
seventh_______________Literature
eighth________________DueDilligence
I don't know what any of the names will be for the items or sections, or how many items, sections, or items per section. As I said, it's very flat. This needs to be fully dynamic which is why this is complicating things for me.
Here is what I've done.
API call to retrieve data. Store data in a state as an array (it comes in as an array of objects).
I create an empty array to store my newly structured data.
I loop through the data with a foreach.
I create a new object for my new data to add to the new array so I can loop over it later.
I first check to make sure the data exists.
To create the headers I check to see if my new empty array is actually empty OR my section_name is not the same as the last one.(in the original data array I got from the API call)
I store the section_names as an object in the new array (newArray.push(newObject)
I've gotten this far. Now I need to take the item_names that correlates to the section_names and store them in the object under each header name, or at least in the same index.
_generateInfo() {
let dataArray = this.state.stepTwoData
let newArray =[]
dataArray.forEach(function(item, index) {
let newObject = {}
if (index > 0) {
if (newArray.length === 0 || item.investor_portal_section_name !== dataArray[index -1].investor_portal_section_name) {
newObject["name"] = item.investor_portal_section_name
newObject["items"] = []
newArray.push(newObject)
}
})
console.log(newArray)
}
I tried pushing the items to the "number" array on my new object and that doesn't seem to work properly. Sometimes it will duplicate my newObject.name
Checking if the newObject.name === the section_names in the array and push it to the "number" array in my new object just creates new key-value pairs so it's still not correlating.
I tried looping through again in the if statement and if section_name === newObject.name then create a newObject and push it, but it would only push one of the items repeatedly instead of going through all of them.
I need to loop through and create a header (one header per different section_name). Then add each item that corresponds to the section_name to it. like this
[
{section_name(header): "Funds",
items: [
{
name: item_name,
sku: item_sku,
url: item_url
},
{
name: item_name,
sku: item_sku,
url: item_url
}]
},
{section_name(header):"Literature",
items: [
{name: item_name,
sku: item_sku,
url: item_url
},
{
name: item_name,
sku: item_sku,
url: item_url
}]}
]
Using associative array (dictionary) to segregate you data itmes by categories will do the job.
I've drafted some POC code that illustrates the idea. The key element there is buildAssociativeArray function
const raw_data = [
{item_name: "first", section_name: "Funds"},
{item_name: "second", section_name: "Funds"},
{item_name: "third", section_name: "Funds"},
{item_name: "fourth", section_name: "Literature"},
{item_name: "fifth", section_name: "Literature"},
{item_name: "sixth", section_name: "Literature"},
{item_name: "seventh", section_name: "Literature"},
{item_name: "eighth", section_name: "DueDilligence"},
]
function buildAssociativeArray(data) {
const dictionary = {};
for (var i = 0; i < data.length; i++) {
const item = data[i];
const section = item.section_name;
var dictEntry = dictionary[section];
if (!dictEntry) {
dictEntry = [];
dictionary[section] = dictEntry;
}
dictEntry.push({
name: item.item_name,
// other fields like sku: item_sku or url: item_url may follow here
});
}
return dictionary;
}
const dictionary = buildAssociativeArray(raw_data);
console.log(dictionary);
/*
At this point
dictionary == {
"Funds": [
{
"name": "first"
},
{
"name": "second"
},
{
"name": "third"
}
],
"Literature": [
{
"name": "fourth"
},
{
"name": "fifth"
},
{
"name": "sixth"
},
{
"name": "seventh"
}
],
"DueDilligence": [
{
"name": "eighth"
}
]
}
*/
// Associcative array dictionary itself allows to further solve you task using for (var key in dictionary) {...} operator
// If however you need to obtain the data structure looking exactly like the one in your question you may go further with following function
function transformAssociativeArray(dictionary) {
const array = [];
for (var key in dictionary) {
const items = dictionary[key];
const newEntry = {
section_name: key,
items: items,
}
array.push(newEntry);
}
return array;
}
const array = transformAssociativeArray(dictionary);
console.log(array);
/*
At this point
array == [
{
"section_name": "Funds",
"items": [
{
"name": "first"
},
{
"name": "second"
},
{
"name": "third"
}
]
},
{
"section_name": "Literature",
"items": [
{
"name": "fourth"
},
{
"name": "fifth"
},
{
"name": "sixth"
},
{
"name": "seventh"
}
]
},
{
"section_name": "DueDilligence",
"items": [
{
"name": "eighth"
}
]
}
]
*/

Filter objects based on a match in another array

I am trying to use Lodash to filter an array of objects based on a match of id's, this is what I have tried:
var team = _.find(this.teams, { 'id': this.newSchedule.team});
_.filter(this.yards, function(yard) {
return _.find(team.yards, { id: yard.id });
});
yards data:
[ { "id": 1, "name": "Test" },{ "id": 2, "name": "Test 2" } ]
team data:
[ { "id": 1, "name": "Team 1", "yards": [{ "id": 1, "name" }] ]
I want this.yards to show the yards based on the yard id from a selected team.
Its hard to understand what you mean, does the yard id match the team id?
If so it sounds like what you need to do is first find the team with the same id then grab that teams yards. Therefore I would use the map function twice:
const result = this
.yards
.map(y => team.find(t => t.id === y.id)) // join with the right team
.map(t => t.yards) // reduce to that teams yards
As team is an array, you need to iterate it before doing the _.find on an individual element in that array. It doesn't help that you called your variable team (singular). teams would make more sense.
Here is how you would change your lodash code:
var yards = [ { id: 1, name: "Test" },{ id: 2, name: "Test 2" } ],
teams = [ { id: 1, name: "Team 1", yards: [{ id: 1, name: "Missing string" }] } ]
result = _.filter(this.yards, function(yard) {
return _.some(this.teams, function(team) {
return _.find(team.yards, { id: yard.id });
});
});
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.4/lodash.min.js"></script>
So this returns the yards that are related to at least one team.

Categories