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
Related
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'}} ] );
I am attempting to parse and retrieve data from an API, but it seems that there is a list that has no name assigned to it, making it impossible for me to call the values within. Here is a masked and run down example of what I am referring to.
(This is the json)
{
"numberOne": [
{
(other information would be in here)
}
]
}
As you can see. number one has a list within itself, which then contains the "other information. The thing is, I cannot send a path to it in javascript (with my method) as I can't simply do convertedJson.numberOne.?.otherInformationValue
Does anyone know how something like this would be done?
Thanks :)
The name of the list in your example is numberOne.
You can access the objects in the list using their index:
exampleJSON = {
"numberOne": [
{
"num1" : "value1"
},
{
"num2" : "value2"
},
]
}
let value1 = exampleJSON.numberOne[0].num1;
let value2 = exampleJSON.numberOne[1].num2;
//...etc
I have a alerts collection in my mongodb..
I wish to get the attributes of the object present in my alerts model, i have written the following code....
Alert.find({},function(err,alerts){
if(err)
console.log(err);
console.log(alerts);
alerts.forEach(function(result){
console.log(result.name);
console.log(result._id);
});
});
In first console, i am getting all the objects of alerts model,
but in second console it is 'Undefined' even result.name is present in the model..
But the _id is generated by mongodb itself and im able to get that id..
From 1st console:
{ __v: 0,
_id: 55128d3a1b35c366eb974285,
brand: 'SanDisk',
name: 'SanDisk Cruzer Blade 8 GB Pen Drives Black (Combo of 2)',
source:
{ name: 'Snapdeal',
productId: '141951',
inStock: true}
}
From 2nd console:
Undefined
From 3rd console
55128d3a1b35c366eb974285
Cannot able to get the problem, what is the correct way of doing this..
Thanks in advance
There is no problem here but you have to understand that MongoDB find() method returns a cursor to the documents that match the query criteria. So what you see in the console.log(alerts) is actually the cursor returned. When the find() method “returns documents,” the method is actually returning a cursor to the documents. So what you see in the first and third console outputs are cursor objects and properties.
You need to add a toArray() method to the resulting cursor from the Alert.find() operation, e.g.
Alert.find({}).toArray(function(err, alerts){
if(err)
console.log(err);
console.log(alerts);
alerts.forEach(function (result) {
console.log(result.name);
console.log(result._id);
});
});
The toArray() method returns an array that contains all the documents from a cursor. The method iterates completely the cursor, loading all the documents into RAM and exhausting the cursor.
I was using mongoose..
and the solution for the above is applying lean() function
i.e
Alert.find({}).lean().exec(function(err,alerts){
if(err)
console.log(err);
console.log(alerts);
alerts.forEach(function(result){
console.log(result.name);
console.log(result._id);
});
});
I'm trying to set up and update some capped collections in MongoDB using Node.js (using the native MongoDB driver).
My goal is to, upon running app.js, insert documents into a capped collection, and also to update existing documents in a capped collection. Both of these are running on setInterval(), so every few seconds.
My questions:
I want to create a collection if the collection does not already exist, but if it does I want to insert a document into it instead. What is the correct way to check this?
With capped collections, should I even be explicitly creating them first before inserting anything into them? Normally I believe you can just insert things into a collection without explicitly creating them first, but in this case I need to ensure they are capped. Once the capped collection exists I know how to insert new documents into it, the problem is I need some way to handle the app being used for the first time (on a new server) where the collection doesn't already exist, and I want to do this creation using node and not having to jump into the mongo cli.
The trick here is that the collection needs to be capped, so I can do something like: db.createCollection("collectionName", { capped : true, size : 100000, max : 5000 } ). That will create the capped collection for me, but every time I call it it will call createCollection() instead of updating or inserting - if I call createCollection(), once the collection already exists, will it completely overwrite the existing collection?
An alternative is to turn a collection into a capped one with: db.runCommand({"convertToCapped": "collectionName", size: 100000, max : 5000 });. The problem with this is that node doesn't see runCommand() as a valid function and it errors. Is there something else that I'm meant to be calling to get this to work? It works in the mongo cli but not within node
What type of query do you use to find the first document in a collection? Again, within the mongo cli I can use db.collections.find() with some query, but within node it states that find() is not a valid function
How would I use collection.update() to add some new fields to an existing document? Lets say the document is some simple object like {key1: "value", key2: "value"} but I have an object that contains {key3: "value"}. Key 3 does not exist in the current document, how would I add that to what currently exists? This is somewhat related to #4 above in that I'm not sure what to pass in as the query parameter given that find() doesn't seem to play well with node.
Regarding your questions 1 - 4 about capped collections and creating them automatically, there are several ways to do this. On the one hand, you could run a script to initialise your database so that it has the capped collections available to your client when you run it for the first time. On the other hand, you could have a check to see if there are any documents in the given collection before inserting a document. If there are, you just insert your document and if there aren't, you create the capped collection and then insert the document as a callback to that function. It would work something like this:
var host = "localhost",
port = 27017,
dbName = "so";
var MongoClient = require('mongodb').MongoClient, Server = require('mongodb').Server;
var mongoclient = new MongoClient(new Server(host, port));
var db = mongoclient.db(dbName);
db.open(function(err, db) {
if(err) throw err;
// Capped collection.
var capped = db.collection('capped');
// Document to be inserted.
var document = { "foo": 1, "bar": 1 }
capped.find().count(function(err, count) {
if(err) throw err;
if (count === 0) {
console.log("Creating collection...");
db.createCollection("capped",
{ "capped": true,
"size": 100000,
"max": 5000 },
function(err, collection) {
if(err) throw err;
// Insert a document here.
console.log("Inserting document...");
collection.insert(document, function(err, result) {
if (err) throw err;
});
});
} else {
// Insert your document here without creating collection.
console.log("Inserting document without creating collection...");
capped.insert(document, function(err, result) {
if (err) throw err;
});
}
});
});
Regarding question 5, you can use findOne() to find a document in the collection, though this is not necessarily the first or last. If you want to guarantee the first or last, you can run a find() with a sort() and limit() of 1. Sorting by _id ascending should give you the first document. More information here.
// Sort 1 for ascending, -1 for descending.
capped.find().sort([["_id", 1]]).limit(1).nextObject(function(err, item) {
console.log(item);
});
Finally for question 6, you just use the $set operator with the update() method. More information here.
capped.update({ "foo": 1 }, { "$set": { "bar": 2 } }, {}, function(err, result) {
console.log(result);
});
Note that you can only update documents in place for capped collections, so you cannot do the insert of the extra field you mention. There are other restrictions enumerated here that you might want to be aware of.
[EDIT: Add updating nested fields in last document.]
If you want to update a nested field in the first or last document (use 1 or -1 in the sort, respectively), you can fetch the document, extract the _id, then perform an atomic update on that document. Something like this:
capped.find().sort([["_id", -1]]).limit(1).nextObject(function(err, item) {
if(err) throw err;
capped.update({ "_id": item._id },
{ "$set": { "timeCollected": 15, "publicIP.ip" : "127.0.0.1" }},
function(err, result) {
if(err) throw err;
console.log(result);
});
});
Note that even when updating a field that exists in a document in a capped collection, you need to ensure that the new value fits in the space allocated for the document. So, for example, updating a string value from "1" to "127.0.0.1" will not necessarily work.
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.