Retrieve Value from MongoDB in Meteor - javascript

So this is how my database looks right now:
{
_id": "r8uoPSvJY36nHgCK9",
"name": "Running",
"category": "leisure",
"duration": "2",
"createdAt": "2/10 16:42:17",
"skills": {
"creativity": 6,
"analytics": 3,
"fitness": 7,
"research": 4,
"communication": 4,
"problemSolving": 3,
"timeManagement": 7,
"leadership": 3,
"selfMotivation": 3,
"teamwork": 4
},
"started": "false",
"finished": "false"
}
How can I query the collection so that I get the value of the creativity field and store it in a variable? I have tried something like:
tasks.find({'skills.creativity': this._id});
but it doesn't appear to work.

.find() returns a cursor - i.e. all the matching records, not just the key that you're looking for.
If you're looking for the creativity field for a single record and assuming you are trying to find the document by its _id and not by the value of the skills.creativity field (which as #Styx points out would be silly) then:
const creativity = tasks.findOne(this._id).skills.creativity;
If you're looking to get the creativity field for all the matching records then:
const creativityArray = tasks.find(query).map((e) => e.skills.creativity);
where query defines the set of documents you're looking for.

Related

How to model the rows in getData() since i have nested JSON data?

I want to display these fields :name, age, addresses_id, addresses_city, addresses_primary for each person into data studio.
My JSON data
{
"data": [
{
"name": "Lio",
"age": 30,
"addresses": [
{
"id": 7834,
"city": "ML",
"primary": 1
},
{
"id": 5034,
"city": "MM",
"primary": 1
}
]
},
{
"name": "Kali",
"age": 41,
"addresses": [
{
"id": 3334,
"city": "WK",
"primary": 1
},
{
"id": 1730,
"city": "DC",
"primary": 1
}
]
},
...
]
}
there is no problem if i don't render the addresses field
return {
schema: requestedFields.build(),
rows: rows
};
//rows:
/*
"rows": [
{
"values": ["Lio", 30]
},
{
"values": ["Kali", 41]
},
...
]
*/
The problem is
I'm not able to model the nested JSON data in Google Data Studio. I
have the problem exactly in the "addresses" field.
Could anyone tell me what format should be for the rows in this case?
As you already know, for each name of your dataset, you clearly have more than one row (one person has multiple addresses). Data Studio only accepts a single data for each field, since arrays are not supported at all. So you need to work on this.
There are some ways to solve this, but always keep in mind that:
getSchema() should return all available fields for your connector (the order doesn't really matter, since Data Studio always sort alphabetically the available fields)
getData() should return a list of values. But here the order is relevant: it should be the same as the parameter passed to getData() (which means the results should be dynamic, sometimes you'll return all values, sometimes not, and the order may change).
Solution 1: Return multiple rows per record
Since you can produce multiple rows for each name, just do it.
To achieve this, your field definition (=getSchema()) should include fields address_id, address_city and address_primary (you can also add address_order if you need to know the position of the address in the list).
Supposing getData() is called with all fields in the same order they were discribed, rows array should look like this:
"rows": [
{
"values": ["Lio", 30, "7834", "ML", 1]
},
{
"values": ["Lio", 30, "5034", "MM", 1]
},
{
"values": ["Kali", 41, "3334", "WK", 1]
},
{
"values": ["Kali", 41, "1730", "DC", 1]
},
...
]
IMO, this is the best solution for your data.
Solution 2: Return one address only, ignoring others
If you prefer one row per person, you can get one of the addresses and display only it (usually the main/primary address, or the first one).
To achieve this, your field definition (=getSchema()) should include fields address_id, address_city and address_primary.
Supposing getData() is called with all fields in the same order they were discribed, rows array should look like this:
"rows": [
{
"values": ["Lio", 30, "7834", "ML", 1]
},
{
"values": ["Kali", 41, "3334", "WK", 1]
},
...
]
Solution 3: Return all addresses, serialized in a field
This is helpful if you really need all information but do not want a complex scheme.
Just create a field called addresses in your field definition (=getSchema()) and write the JSON there as a string (or any other format you want).
Supposing getData() is called with all fields in the same order they were discribed, rows array should look like this:
"rows": [
{
"values": ["Lio", 30, "[{\"id\": 7834, \"city\": "ML", \"primary\": 1}, {\"id\": 5034, \"city\": \"MM\", \"primary\": 1}]"]
},
{
"values": ["Kali", 41, "[{\"id\": 3334, \"city\": \"WK\", \"primary\": 1}, {\"id\": 1730, \"city\": \"DC\", \"primary\": 1}]"]
},
...
]
This solution may appear senseless, but it is possible to interact with this data later in DataStudio using REGEX if really needed.
Solution 4: Create a different field for each address
If you're sure all records has a maximum number of addresses (in you example, both names have 2 addresses, for example), you can create multiple fields.
Your field definition (=getSchema()) should include fields address_id1, address_city1, address_primary1, address_id2, ... address_primaryN.
I wouldn't explain how rows should look like in this situation, but it is not hard to guess with the other examples.

JSX filter items in array if property matches string, otherwise show all items

I have created some fake "tasks" json and I need to list it out in JSX which I have done. Now I have some buttons that allow you to view tasks by "All", "Quotes" or "Other". Each task in the JSON file has a "type" property which either has "Quotes" or "Other".
Here is the code where I map through the array and show the information for each task:
<section className={styles.tasks_list}>
{tasksData.map(({ customer_id, account_name, days }) => {
return (
<article key={customer_id} className={styles.task}>
<span className={styles.task_name}>{account_name}</span>
<span className={`${styles.task_days}`}>{getDaysDue(days)}</span>
<div className={styles.task_buttons}>
<button className={`${styles.task_button} ${styles.edit}`}>
<MdModeEdit />
</button>
<button className={`${styles.task_button} ${styles.delete}`}>
<MdDeleteForever />
</button>
</div>
</article>
);
})}
</section>
Of course this displays ALL data.
I have state which updates and saves the current active tab's value - so if the quote button is selected, I can access the variable activeTab and get the string "Quotes", same for "Other". When the All button is clicked it changes this string to "All". Now none of my json objects have the "All" type because I want it to display everything regardless of type.
Here is the json:
[
{
"account_name": "Misty's Gym",
"customer_id": 1,
"days": {
"days_due": 1,
"overdue": false
},
"type": "Quotes"
},
{
"account_name": "Brock's Diner",
"customer_id": 2,
"days": {
"days_due": 0,
"overdue": false
},
"type": "Quotes"
},
{
"account_name": "Samurai Champloo's Fish Bar",
"customer_id": 3,
"days": {
"days_due": 5,
"overdue": false
},
"type": "SSL Setup"
},
{
"account_name": "Tiny Rebel",
"customer_id": 4,
"days": {
"days_due": 7,
"overdue": true
},
"type": "Domains"
},
{
"account_name": "Matalan",
"customer_id": 5,
"days": {
"days_due": 13,
"overdue": false
},
"type": "Other"
},
{
"account_name": "Lowes Soft Drinks",
"customer_id": 6,
"days": {
"days_due": 1,
"overdue": false
},
"type": "SEO Setup"
},
{
"account_name": "Snack 'n' Go",
"customer_id": 7,
"days": {
"days_due": 2,
"overdue": true
},
"type": "Quotes"
},
{
"account_name": "Jeronemo",
"customer_id": 8,
"days": {
"days_due": 5,
"overdue": false
},
"type": "Quotes"
}
]
How can I filter by the strings but then show all of them if the activeTab variable is set to "All"? I might be overthinking this. I've run an if statement where it shows the items if (task.type === activeTab) { shit out jsx with information where the type matches } but I don't know how to then show all.. if I was to do an else statement I'd need to copy the exact same JSX which I want to avoid. Also it causes all tabs to just show every task.
I feel like there's something obvious I'm not thinking about. My code is a mess and it's almost 5am, should probably sleep!
Any help appreciated, thank you.
We just need to change the data before map. I am just showing the changed part in your code.
// ... same code
tasksData.filter((task) => (activeTab === 'All' ? true : task.type === activeTab)).map
// ... same code
In here we are looping over the task list beforehand and only accepting the task whose task.type is equal to activeTab, with just a tweak that we will use this check only if activeTab is not equal to All
The algorithm is pretty much as you have defined in your question. From your question, it isn't clear why 'Also it causes all tabs to just show every task'
I would use the following logic to handle this.
If activeTab === options
Filter tasks with type options and display
else if activeTab === quotes
Filter tasks with type quotes and display
else if activeTab === all
Display all tasks
I don't see why this has any problems in logic, so it shouldn't display every task in all tabs.

Multiple single results from firebase

I have an array of elements which contain some ids. I need to connect to firestore and fetch only the records which have each specified id.
My array:
var ids = { 101, 201, 303}
and my firestore documents:
{
"users": {
{
"id": 1,
"name": "name1",
"otherData:" "otherData"
},
{
"id": 2,
"name": "name1",
"otherData:" "otherData"
},
{
"id": 3,
"name": "name1",
"otherData:" "otherData"
},
...
{
"id": 1000,
"name": "name1",
"otherData:" "otherData"
}
}
}
How can I do that efficiently using db.collection('coll1').where() statements?
I have tried to fetch the data using forEach like this:
ids.forEach(id => {
let result = db.collection('coll1').where('id', '==', id).get();
...
});
But each time I try doing it this way, it does not work.
I am new to the firestore environment and not sure how to do such an operation. Please help.
You can use Firstore compound queries for this. Link to officials docs here.
Use the in operator to combine up to 10 equality (==) clauses on the same field with a logical OR. An in query returns documents where the given field matches any of the comparison values.
Similarly, use the array-contains-any operator to combine up to 10 array-contains clauses on the same field with a logical OR. An array-contains-any query returns documents where the given field is an array that contains one or more of the comparison values
You need to change ids to array type
var ids = [ 101, 201, 303 ]
Query
db.collection("coll1").where("id","in", ids).get();

Merging Data Objects in Javascript for Display in VueJS

first time question asker.
I am working on trying to bring together data from two different API endpoints being served from a Django Rest Framework backend and rendering the display with VueJS on the frontend.
The challenge I am faced with is merging my questionnaire sections and questions with the associated answers. The questionnaire information is coming from one endpoint and the answers from another. Below is a sample of the data.
Sections & Questions Data
{
"survey_id": 2,
"survey_name": "My Survey",
"instructions": "Instructions.",
"other_header_info": ""
"section": [
{
"section_id": 2,
"section_name": "Section Name",
"section_title": "Section Title",
"section_instructions": "Some Instructions",
"section_required_yn": true,
"question": [
{
"question_id": 2,
"question_name": "Question One.",
"question_subtext": "None.",
"answer_required_yn": true,
"input_type_id": {
"id": 3,
"input_type_name": "Dropdown"
},
"option_group_id": "1 - 10",
"allow_multiple_option_answers_yn": false
},
{
"section_id": 3,
"section_name": "Another Section",
"section_title": "Section Title",
"section_instructions": "Section Instructions",
"section_required_yn": true,
"question": [
{
"question_id": 10,
"question_name": "Another question to be answered",
"question_subtext": "None.",
"answer_required_yn": true,
"input_type_id": {
"id": 3,
"input_type_name": "Dropdown"
},
"option_group_id": "1 - 10",
"allow_multiple_option_answers_yn": false
},
Answers Data
"results": [
{
"id": 100,
"answer_numeric": 4,
"answer_text": null,
"answer_yn": null,
"answer_group": "4-ojepljuu",
"question_id": 2,
},
{
"id": 101,
"answer_numeric": 1,
"answer_text": null,
"answer_yn": null,
"answer_group": "4-ojepljuu",
"user_id": 4,
"question_id": 5,
},
I know I need to match up the question_id fields from both the questionnaire sections data and the answers data. The problem I am facing is, how does one go about doing this?
I would like to create a new set of data that appends the answer data to the question data. I am also trying to build in some flexibility since I have multiple survey types with a variable number of sections and questions.
Trying to keep the data in sections so I can render the frontend views the way I would like.
I've tried looping through sections and questions, using the example I found here: Merge two array of objects based on a key but haven't had much luck.
Still relatively new - any information, guidance or even a working example would be greatly appreciated.
Update:
I've managed to make a bit of progress on this. Writing a small test function, I can now update the section/question object with some dummy data.
var a = this.answers;
var s = this.section;
var newObj = { answer_text: "test1", answer_numeric: "test2" };
for (var idx3 = 0; idx3 < s.length; idx3++) {
for (var idx4 = 0; idx4 < s[idx3].question.length; idx4++) {
Object.assign(s[idx3].question[idx4], newObj);
}
}
Each of the question objects within each section now includes the answer_text and answer_numeric key/value pairs.
The next challenge is to find the matching answer data based on matching the appropriate question_id within the answer object to the question_id in the question object.
Any thoughts?
I would store results as a dictionary, instead of an array:
var results_to_dict = function (results) {
var dict = {};
results.forEach(r => dict[r.question_id] = r);
return dict;
};
results = results_to_dict(results);
Now, you can show your questions in your template with their answers:
<div v-for="question in section.questions" :key="question.question_id">
<p>Question: {{question.question_name}}</p>
<p>Answer: {{answers[question_id].text}}</p>
</div>

JSON list optimization

I want to create a JSON API that returns a list of objects. Each object has an id, a name and some other information. API is consumed using JavaScript.
The natural options for my JSON output seems to be:
"myList": [
{
"id": 1,
"name": "object1",
"details": {}
},
{
"id": 2,
"name": "object2",
"details": {}
},
{
"id": 3,
"name": "object3",
"details": {}
},
]
Now let's imagine that I use my API to get all the objects but want to first do something with id2 then something else with id1 and id3.
Then I may be interested to be able to directly get the object for a specific id:
"myList": {
"1": {
"name": "object1",
"details": {}
},
"2": {
"name": "object2",
"details": {}
},
"3": {
"name": "object3",
"details": {}
},
}
This second option may be less natural when somewhere else in the code I want to simply loop through all the elements.
Is there a good practice for these use cases when the API is used for both looping through all elements and sometime using specific elements only (without doing a dedicated call for each element)?
In your example you've changed the ID value from 1 to id1. This would make operating on the data a bit annoying, because you have to add and remove id all the time.
If you didn't do that, and you were relying on the sorted order of the object, you may be in for a surprise, depending on JS engine:
var source = JSON.stringify({z: "first", a: "second", 0: "third"});
var parsed = JSON.parse(source);
console.log(Object.keys(parsed));
// ["0", "z", "a"]
My experience is to work with arrays on the transport layer and index the data (i.e. convert array to map) when required.

Categories

Resources