Update a field to be further nested in a document - MongoDB/Node - javascript

I am writing a migration with migrate-mongo and the Node driver for Mongo which both have not-so-great documentation. I am trying to take a field and nest it one level further. Here is an example of the original structure:
{
"_id": {"$oid":"xxxxxxxx"},
"module": "lalala",
"settings": {
"yAxis": {
"title": {
"text": "TITLE"
}
}
}
I would like to take the yAxis field and its contents and nest it under a "highcharts" field so it ends up like this:
"settings": {
"highcharts": {
"yAxis": {
"title": {
"text": "TITLE"
}
}
}
}
I saw this Update field with value from a nested field and was hoping I could use that $ operator to just take the yAxis contents and stick them back in but that isn't working. (The yAxis field now just reads the string literal '$settings.yAxis')
async up(db) {
const panels = db.collection('panels');
await panels.updateMany({module: 'lalala'},
{$set: {'settings.highcharts.yAxis': '$settings.yAxis'}});
await panels.updateMany({module: 'lalala'},
{$unset: {'settings.yAxis': ''}});
I also thought maybe I should iterate through the documents, parse them as JSON and grab the contents of yAxis, and insert that into a new 'highcharts' field, but that's using await in a forEach which doesn't work.
I ideally am doing this async so that I can do multiple operations in a single migration. Otherwise I would have to set the new 'highcharts' field in one migration and unset the old 'yAxis' in a different migration which could lead to problems if one fails but the other doesn't.
Somewhat stuck here, anything helps. Thanks!

OK I was close and I dont understand why, but putting brackets around my $set was what I needed.
await panels.updateMany({module: 'lalala'},
[ {$set: {'settings.highcharts.yAxis': '$settings.yAxis'}} ] );

Related

How to hide div if conditions from GET request data are met

I have a div that's being populated by GET request data. I want to make it so that if certain conditions are not met (there isn't any data) then the div is hidden. It was working when I was using a local JSON file, but since I switched to REST and axios I've had to convert what I have.
When I run console.log(admText.length) I'm getting a 0 and the div is hidden in the browser, but the user's data that I've rendered does contain data. Therefore, their page should show that div.
I have a feeling that my if statement is in the wrong place, but I'm not sure where it could go. Putting it in the let admText block results in an error.
JS snippet:
import $ from 'jquery';
import DataTable from 'datatables.net';
export default class {
constructor() {
}
loadAdmData(response) {
let admText = response.map(function(val) {
return {
"Status": val.AdmStatus,
"Classification": val.Classification
}
})
if (admText.length == "") $("#adm-tab").hide();
// if (!admText.length) $("#adm-tab").hide(); // was working w/ local JSON file
console.log(admText.length); // shows `0`, which isn't correct
$('#adm-table').DataTable({
columns: [
{ data: "Status" },
{ data: "Classification" }
... etc
Are you sure response is an array? if you're getting it from a GET it could be a JSON string.
.map() is going to return an array so admText is an array and since you're getting .length as '0' that means your mapping function is failing for some reason.
you should try console.log(response); and console.log(admText); to see what you're putting inside of the map and what you're getting out of it.

Fusionchart zoomchart show certain section programmatically

I am using a 'zoomline' Chart from the fusioncharts framework.
I am displaying some values which change over time. Now I want to implement a function to directly address one month or any other timespan with something like this:
new FusionCharts({
"type": "zoomline",
"id": "example",
"renderAt": "chartContainer",
"dataSource": {
"chart": {
{
"xAxisZoomBegin": "2018-03-01"
},
{
"xAxisZoomEnd": "2018-04-01"
}
},
...
},
...
});
Whereas xAxisZoomBegin and xAxisZoomEnd don't really exist but I'm looking for something like that but haven't found anything in their documentation. Do you have any advice how I can do this?
FusionCharts supports methods like zoomOut, zoomTo, and resetChart which will help you to achieve your requirement.
Check out this doc to know more about these methods.
Samples are given in the doc itself, you can refer them for your implementation.

Oboe.js - how to work with chainable method and retrieving ancestor value

I am using oboe.js and and i want to retrieve data from the node "sections" and also map the ancestor profile_namespace and owner_name to the data retrieve from sections node (see json file extract below).
JSON FILE EXTRACT (myjson.json):
{
"data": [{
"profile_namespace": "DS",
"tutorial": {
"owner_name": "Dominic",
"picture_url": "/picture.jpg",
"title": "The code",
"url": "/Dominic/thecode/",
"sections": [{
"episode_url": "/tutorial/intro/symphony-of-war/",
"artist": "MasterOrchestra",
"title": "Symphony of War"
}, {
"episode_url": "/tutorial/mainshow/musicproductiontip1/",
"artist": "DStone",
"title": "Music production tip 1"
}, {
"episode_url": "/tutorial/outrothe/nextshow/",
"artist": "MasterOrchestra",
"title": "Next show"
}]
}
}]
}
Right now i am only able to retrieve data from the node "sections" but i saw in the documentation that .node return chainable method and that it is possible to use the notion of "ancestors" to retrieve data from the parent.
Does anyone can explain me how to use this method (see my code below)?
CODE
var oboe = require('oboe');
var fs = require('fs');
var SetList = require('fs');
var setList = [];
var showInfo = require('fs');
oboe(fs.createReadStream('/myjson.json'))
.node({
'sections': function(node) {
setList.push(node);
showInfo = fs.createWriteStream('/showInfo.json');
showInfo.write(JSON.stringify(setList));
}
});
Thanks for your help!
Dominic
Let me know if I misunderstood parts of your question and I update my answer.
Using ancestors in Oboe
The callback function you pass to a node listener will fire with three arguments. The first is the node in the tree which has been matched, the second will be an array representing the path to that node, and the third will an array of objects representing the ancestors of that node. This is documented near the end of the node-event section of the API.
.node({
'sections': function(sections, path, ancestors) {
var grandparent = ancestors[ancestors.length - 2];
console.log(grandparent.owner_name); // Dominic
var greatGrandparent = ancestors[ancestors.length - 3];
console.log(greatGrandparent.profile_namespace); // DS
}
});
Other things
Here are some unrelated things I think are worth mentioning
You can probably remove this line, since the variable SetList is not being used.
var SetList = require('fs');
You don't need to initialize setList to an instance of the fs module. Since you're going to redefine it later, you can just declare that variable without instantiating it. Even better, you could define it within the callback since it's the only place it's used.
Node (at least v0.10.41) throws an error if you call fs.createReadStream or fs.createWriteStream on a string starting with '/'. I would suggest calling them with './myjson.json' and 'showInfo.json'
I would suggest using the shorthand way of registering a node listener in Oboe. This one is just a stylistic preference. The other syntax can be useful if you're registering multiple listeners, but I think chaining is just as good in that situation.
My suggested implementation of the code you posted
var oboe = require('oboe');
var fs = require('fs');
oboe(fs.createReadStream('./myjson.json'))
.node('sections', function(sections, path, ancestors) {
var mutatedSections = sections;
// change mutatedSections however you want
var showInfo = fs.createWriteStream('./showInfo.json');
showInfo.write(JSON.stringify(mutatedSections));
}
});

Mongo/Mongoose - markModified not working

I have the following query:
Section.find({"clause": sub.section}, function(err, docs){
var detail = parseInt(sub.detail);
docs[0].subClauses[0].additionalDetails[detail-1].percentile = sub.percentile;
docs[0].markModified("subClauses");
docs[0].save(function(err, doc){
if(err) { return callback(err) };
callback();
})
})
When I log the doc inside the .save function it appears to have saved successfully. However on querying the db elsewhere the save has not happened. The object its trying to save to is 3 deep like this:
[
{
"clause": "1",
"subClauses:
[
{
"clause":"1.1",
"additionalDetails:
[
{
"detail": "1",
"content": "whatever"
}
]
}
]
}
]
With several items inside each array.
Am I not able to save data to the nested array object using Mongo?
If I understand what you are trying to do, then I think what you are wanting to use is the Mongo Position Operator ($). This is used to index nested arrays in a document. In your current code you are only referencing the first object in the array. Using the position operator you will be able to reference other positions based of some other data, such as a query.
Here is the documentation for the operator: http://docs.mongodb.org/manual/reference/operator/update/positional/
And here is another Stack Overflow response which may help a bit also:
MongoDB $ operator

d3 csv readin to objects in array

I am currently trying to use the d3 framework for a university visualisation approach.
For testing purpose I want to read a csv-file and parse the rows to objects inside an array.
My csv looks like:
ID, Referred To, TimeStamp, Votes, Comment
So I want to read it with the following lines:
d3.csv("test_comments.csv", function(data) {
commentlist = data.map(function(d) {
return[+d["ID"],
+d["Referred To"],
+d["TimeStamp"],
+d["Votes"],
+d["Comment"]
]
});
});
But if I want to readout the values afterwards I am just getting "undefined"
I also tried the way mbostock described in this thread:
csv to array in d3.js
but working with a global variable is not working either.
var commentlist;
d3.csv("test_comments.csv", function(data) {
commentlist = data.map(function(d) {
return[+d["ID"],
+d["Referred To"],
+d["TimeStamp"],
+d["Votes"],
+d["Comment"]
]
});
});
console.log(commentlist);
Am I understanding something wrong?
Maybe you have a solution for me.
var commentlist=[];
d3.csv("test_comments.csv", function(data) {
commentlist=data;
});
console.log(commentlist);
What I know is, In the call back data object will contain array of JSON objects of csv file's all rows of data, that each row data is pushed as a JSON format into the data array.
As below
[{"ID": valueFromtheRow, "Referred To": value, "TimeStamp": value, "Votes":value, "Comment":value}]
The call back function is called by passing the array of JSONs.
So data object will look like
data=[{"ID": valueFromtheRow, "Referred To": value, "TimeStamp": value, "Votes":value, "Comment":value}];
Hope you understood...If not ask me.
I think the reason you got { console.log(commentlist) } undefined is that inside d3.csv the callback function is parsed and called last by browser, and { console.log(commentlist) } is called earlier even though it appears at the bottom of your code. So the moment when { console.log(commentlist) } is called, { commentlist } is actually undefined (only declared).
That being said, just try putting { console.log(commentlist) } inside the callback and it should do the job.

Categories