Cannot list keys within object - javascript

I have a state variable projects which should store a dictionary of arrays, where the key is id of the organisation that owns the project, and the array consists of objects storing information about the project. For example:
{
orgId123: [
project1: {
name: "my cool project",
status: "submitted"
},
projectAwesome: {
name: "Stan's project",
status: "draft"
}
],
orgUSA: [
newProj234: {
name: "another great project",
status: "submitted"
}
]
}
I try to get a list of all organisation IDs using Objects.keys(projects), however that returns an empty array.
I suspect that somehow my projects variable is structured wrongly. When I console.log the contents of projects, I get:
Notice how the root level object says just {}.
When I tried to re-create what the projects variable should look like and logged that, I saw a slightly different output:
In this manually created object, the root-level object is shown as {orgId1}: Array(1) instead of the previously-shown {} (on the actual object).
What does this say about how the object is structured and why can I not get a list of keys from the first object using Object.keys()?
For context, I create the original variable using the following code:
async function fetchProjects() {
// Load list of organisations that the user is a member of
const organisationsSnapshot = await getDocs(query(
collection(db, 'organisations'),
where(`members.${user.uid}`, '!=', null)
))
const organisations = organisationsSnapshot.docs.map(organisationSnap => ({
...organisationSnap.data(),
id: organisationSnap.id
}))
// Load list of projects for each organisation the user is a member of
const projectsDict = {}
organisations.forEach(async (organisation) => {
const projectsQuery = query(collection(db, `organisations/${organisation.id}/projects`))
const projectsSnap = await getDocs(projectsQuery)
projectsDict[organisation.id] = projectsSnap.docs.map(projectSnap => ({
...projectSnap.data(),
id: projectSnap.id
}))
})
setProjects(projectsDict)
}

You cannot have an array of key:values. You should wrap it in {}.
[ key1: value1, key2: value2, ] //Unexpected Token
[ { key1: value1 }, { key2: value2 }, ] //Good to go
So instead of:
{
orgId123: [
project1: {
name: "my cool project",
status: "submitted"
},
projectAwesome: {
name: "Stan's project",
status: "draft"
}
],
orgUSA: [
newProj234: {
name: "another great project",
status: "submitted"
}
]
}
You should have:
{
orgId123: [
{
project1: {
name: "my cool project",
status: "submitted"
}
},
{
projectAwesome: {
name: "Stan's project",
status: "draft"
}
}
],
orgUSA: [
{
newProj234: {
name: "another great project",
status: "submitted"
}
}
]
}
OR
{
orgId123: {
project1: {
name: "my cool project",
status: "submitted"
},
projectAwesome: {
name: "Stan's project",
status: "draft"
}
},
orgUSA: {
newProj234: {
name: "another great project",
status: "submitted"
}
}
}
Honestly, I would structure your projects as follows:
const organisations = [{
orgId: "orgId123",
projects: [{
projectId: "project1",
name: "my cool project",
status: "submitted"
}, {
projectId: "projectAwesome",
name: "Stan's project",
status: "draft"
}]
},
{
orgId: "orgUSA",
projects: [{
projectId: "newProj234",
name: "another great project",
status: "submitted"
}]
}
]
//This way, organisations is an array of organisations,
//which is an object that has orgId, projects which is an array of its projects.
//It will be much more intuitive to work with while iterating over it.
//Such as if you need to display all the orgIds,
console.log("Organisation IDs:")
for (const org of organisations) {
console.log(org.orgId)
}
console.log("=================");
//If you need all project IDs and names:
console.log("Projects:")
for (const org of organisations) {
console.log(`Organisation ${org.orgId} has the following projects:`)
for (const proj of org.projects) {
console.log(`Project ID ${proj.projectId}: ${proj.name}`)
}
console.log("=================");
}
console.log("=================");

Related

How to filter this array based on an array of object within an array of object

I`ve been stucked in this problem for a few hours already. Suppose my lead object has a matched_listings field and the match listings field has a listing.contact_details array of object with an email field inside, I need to filter my leads data based on the listing_contact_details array of object, basically return all leads that matches the email within the listing_contact_details of the matched_listings and the email variable i got from req.query. I tried implementation from using sets, filter, map, includes method but i cant seem to get it. Would appreciate some help :)
const getLeads = async (req, res, next) => {
const email = req.query.email;
let leads;
try {
leads = await Lead.find().populate({
path: "matched_listings",
match: { "listing_contact_details.email": email },
});
} catch (err) {
const error = new HttpError("Something went wrong", 500);
return next(error);
}
let matchedLeads;
//filter logic
res.json({ response: 'success'});
};
//Sample data set:
leads = [
{
matched_listings: [
{
listingName: "sample name",
listing_contact_details: [
{
email: "email-sample#gmail.com",
name: "sample name of contact detail",
},
],
},
{
listingName: "sample name2",
listing_contact_details: [
{
email: "email-sample#gmail.com",
name: "sample name of contact detail",
},
],
},
],
leadName: "sample name",
leadField: "sample field",
},
{
matched_listings: [
{
listingName: "sample name",
listing_contact_details: [
{
email: "sample-2#gmail.com",
name: "sample name of contact detail",
},
],
},
{
listingName: "sample name2",
listing_contact_details: [
{
email: "sample-2#gmail.com",
name: "sample name of contact detail",
},
],
},
],
leadName: "sample name 2",
leadField: "sample field 2",
},
];
If you wan to filter based on a single email you can try this:
leads = await Lead.find({
"matched_listings.listing_contact_details.email": email
});

Can't regroup an array

I do a simple explorer on Angular (there are a list of directories that contain other directories or text files). The question is: I receive the following data from the server ("path" is the path of the folder, ids of parent directories):
[
{
id: "6np5E3yyEISXLNX9muyt",
name: "sec list",
path: ["", "GnBOclNO1v3n9FW7aGv0", "X5YNJ6Vco2BtGxNZVsYV"],
},
{
id: "GnBOclNO1v3n9FW7aGv0",
name: "In aeroport",
path: [""],
},
{
id: "H6AvpwXc49v4oDRWSjym",
name: "Delete",
path: [""],
},
{
id: "LQ73vVoTuw9xd40jMs3j",
name: "Aeroport list",
path: [""],
},
{
id: "X5YNJ6Vco2BtGxNZVsYV",
name: "Bordery words",
path: ["", "GnBOclNO1v3n9FW7aGv0"],
},
{
id: "jWeClRAw55Er8z0Ow9uq",
name: "mail list",
path: ["", "GnBOclNO1v3n9FW7aGv0", "X5YNJ6Vco2BtGxNZVsYV"],
}
];
How can I regroup that into code below? I know recursion is needed, but I can not understand, how to do it right. Help me, please.
[
{
id: "GnBOclNO1v3n9FW7aGv0",
name: "In aeroport",
children: [
{
id: "X5YNJ6Vco2BtGxNZVsYV",
name: "Bordery words",
children: [
{
id: "6np5E3yyEISXLNX9muyt",
name: "sec list",
},
{
id: "jWeClRAw55Er8z0Ow9uq",
name: "mail list",
}
],
}
],
},
{
id: "H6AvpwXc49v4oDRWSjym",
name: "Delete",
},
{
id: "LQ73vVoTuw9xd40jMs3j",
name: "Aeroport list",
},
]
Simple DFS solves the problem, but there are multiple ways to do this. One way is below
var paths = [
{
id: "6np5E3yyEISXLNX9muyt",
name: "sec list",
path: ["", "GnBOclNO1v3n9FW7aGv0", "X5YNJ6Vco2BtGxNZVsYV"],
},
{
id: "GnBOclNO1v3n9FW7aGv0",
name: "In aeroport",
path: [""],
},
{
id: "H6AvpwXc49v4oDRWSjym",
name: "Delete",
path: [""],
},
{
id: "LQ73vVoTuw9xd40jMs3j",
name: "Aeroport list",
path: [""],
},
{
id: "X5YNJ6Vco2BtGxNZVsYV",
name: "Bordery words",
path: ["", "GnBOclNO1v3n9FW7aGv0"],
},
{
id: "jWeClRAw55Er8z0Ow9uq",
name: "mail list",
path: ["", "GnBOclNO1v3n9FW7aGv0", "X5YNJ6Vco2BtGxNZVsYV"],
}
];
var dfs = function( parentJson , path){
for(var i=0;i<paths.length;i++){
if(paths[i].path.join("") == path ){
var child = {id:paths[i].id,name:paths[i].name,children:[]}
parentJson.push(child)
dfs(child.children,path+paths[i].id)
}
}
}
var json = [];
dfs(json,"")
console.log(json)
You could do this in two phases:
First make a nested object structure where the children properties are not arrays, but objects, where the object keys are the id values. That way you can quickly navigate in that structure with a given path, and extend/deepen it at the same time.
In a final phase, you can use recursion to walk through that tree structure to convert those children properties to arrays.
Here is how that looks:
function makeTree(data) {
// drill down the object structure, where children properties
// are nested objects with id values as keys.
let result = {}; // root of the tree data structure
for (let {id, name, path} of data) {
Object.assign(path.slice(1).concat(id).reduce((acc, key) => {
if (!acc.children) acc.children = {};
if (!acc.children[key]) acc.children[key] = {};
return acc.children[key];
}, result), { id, name });
}
return (function unkey(node) {
// Convert children objects to arrays
if (node.children) node.children = Object.values(node.children).map(unkey);
return node;
})(result);
}
let data = [{id: "6np5E3yyEISXLNX9muyt",name: "sec list",path: ["", "GnBOclNO1v3n9FW7aGv0", "X5YNJ6Vco2BtGxNZVsYV"],},{id: "GnBOclNO1v3n9FW7aGv0",name: "In aeroport",path: [""],},{id: "H6AvpwXc49v4oDRWSjym",name: "Delete",path: [""],},{id: "LQ73vVoTuw9xd40jMs3j",name: "Aeroport list",path: [""],},{id: "X5YNJ6Vco2BtGxNZVsYV",name: "Bordery words",path: ["", "GnBOclNO1v3n9FW7aGv0"],},{id: "jWeClRAw55Er8z0Ow9uq",name: "mail list",path: ["", "GnBOclNO1v3n9FW7aGv0", "X5YNJ6Vco2BtGxNZVsYV"],}];
console.log(makeTree(data));
Note that the first value of the path value is never used. It seems to always be the empty string.

Targeting Specific Array Element with Assignment Destructuring

I am using some assignment destructuring in my MongoDB/Node backend in order to handle some post-processing. I'm just trying to understand how this destructuring works, and if, in the case of an array of multiple elements and nested arrays, if I can input the element I want to target.
Take for instance this code:
services: [
,
{
history: [...preSaveData]
}
]
} = preSaveDocObj;
My assumption is that the "," in "services" for the above code will default to looking at the first element in the array. Correct?
Now, if I have a document structure that looks like this (see below), and I know I want to target the "services" element where "service" is equal to "typeTwo", how would I do that?:
{
_id: 4d39fe8b23dac43194a7f571,
name: {
first: "Jane",
last: "Smith"
}
services: [
{
service: "typeOne",
history: [
{ _id: 121,
completed: true,
title: "rookie"
},
{ _id: 122,
completed: false,
title: "novice"
}
]
},
{
service: "typeTwo",
history: [
{ _id: 135,
completed: true,
title: "rookie"
},
{ _id: 136,
completed: false,
title: "novice"
}
]
}
]
}
How can I edit this code (see below) to specifically target the "services" array where "service" is equal to "typeTwo"?
services: [
,
{
history: [...preSaveData]
}
]
} = preSaveDocObj;
Don't overdestructure, just find:
const { history: [...preSavedData] } = doc.services.find(it => it.serice === "typeTwo");

Sequelize, how structuring return value inside single object

Sorry for my bad English. I have used fastify for my javascript framework and Postgresql as my database and sequelize as my ORM. But problem occured when i have multiple models.
This is my Code :
// Extract Db
const { student} = this.models
return student.findById(id, {
include: [
{ all: true },
],
limit: 1,
})
The result is :
// Result
{
id: 1,
name: "my beastiful name",
class: "...",
...
// School Object
school: {
id: 23,
name: "My School name",
...
}
}
But what i want is :
// Result
{
// Student Object
student: {
id: 1,
name: "my beastiful name",
class: "...",
...
},
// School Object
school: {
id: 23,
name: "My School name",
...
}
}
Should i use multiple "find" to achive this result.

Javascript Array Manipulation - Is there a more declarative approach?

Thanks for taking a look here. I'm working with an API, and need to change the format of the data. Here's an example of the return data:
data: [
{
status: "planned work",
name: "123"
},
{
status: "all good",
name: "nqr"
}
];
Each train line has a name like "123" or "nqr", and I want to split each train into their own objects so that it would look something like this:
data: [
{
status: "planned work",
name: "1"
},
{
status: "planned work",
name: "2"
},
{
status: "planned work",
name: "3"
},
{
status: "all good",
name: "n"
},
{
status: "all good",
name: "q"
},
{
status: "all good",
name: "r"
}
];
I have some working code which splits the name and uses nested .forEach loops to push items to an array. Working code:
function formatLinesData(lines) {
var trains = [];
lines.forEach( line => {
line.name.split("").forEach(train => {
trains.push({name: train, status: line.status});
});
});
return trains;
}
Is there a way to accomplish this without the nested loops? Looking for an elegant solution if you have one.
Thanks
You might do as follows;
var data = [
{
status: "planned work",
name: "123"
},
{
status: "all good",
name: "nqr"
}
],
newData = [].concat(...data.map(o => o.name.split("").map(c => ({status: o.status, name: c}))));
console.log(newData);
You can use reduce - initialize it with an empty array, and iterate over the data
array using your logic.
data.reduce((prev,curr) => {
for (let i=0; i<curr.name.length; i++) {
prev.push({ name : curr.name[i], status : curr.status});
}
return prev;
},[]);

Categories