Problems reading MongoDb collection with Node.js - javascript

I have problems reading this collection with mongoose and Node.js:
I have one JSON inside my Collection and i try to read this with this code:
materias.find().exec(function(err1,materias){
if(err1){console.log(err1); return next();}
for(x=0;x<materias.length;x++){
//console.log(materias[x].Nombre);
//var arreglo=materias[x].Horario[0].Dia; // TRY ONE
var arreglo=JSON.parse(materias[x].Horario[0]); // TRY TWO
console.log(arreglo[0]);
}
//RESPONSE TRY ONE
console.log(arreglo) UNDEFINED
//RESPONSE TRY TWO
undefined [
//if I use JSON.stringify the response is {[object][object]...
enter code here

You don't need to parse JSON manually with mongoose.
You get undefined because you define variable arreglo inside the loop but try to access it outside of it. This should work:
materias.find().exec(function(err1,materias){
if(err1){console.log(err1); return next();}
for(x=0;x<materias.length;x++) {
var arreglo = materias[x].Horario[0]; // TRY TWO
console.log(arreglo);
}

What i suppose the error is: you have database named as materias and you are using the same name for the returned collection. Try changing the return name collection to something other.
materias.find().exec(function(err1,change_name_here){
//required code
}

FINALYYYYYYYYYY i fixed it changing my mongoose model
I had this:
var materias=new Schema({
Nombre:{type:String, required:true},
Docente:{type:String, required:true},
Horario:{type:String, required:true}
});
module.exports = materias;
and change for this:
Horario:[{Dia:String, Hora:String, Tiempo:String}]
for reading:
for(x=0;x<materias.length;x++){
var arreglo=materias[x].Horario; // TRY TWO
console.log(arreglo[0].Dia);
}

Related

Mongoose: Unable To Save Data To Empty Object

Here is my situation:
I have a simple Schema that has an object called commands which I originally set to {}.
commands:{}
When I went to add a document to the database, I looped through a file of commands and added them to the object by doing command["command"] = "blah blah";. The way I did that is as follows (The code I work is quite old):
Guild.findOne({guildId:serverId}).then(x=>{
x.commands = {};
for(let command of Object.values(commandInfo)){
if(!command.name) continue;
const getSubs = ()=>{
const subArray = {};
if(!command.subCommands) return;
for(let subs of Object.values(command.subCommands)){
subArray[subs.name] = {
access:subs.access,
disabled:subs.disabled
}
}
x.commands[command.name].subCommands = subArray;
}
x.commands[command.name] = {
access:command.access,
bounded:command.bounded,
disabled:command.disabled,
}
getSubs();
}
console.log("Success!");
x.save();
});
The commands contain the following (I'll use two commands for my example):
work:{
access:"All",
bounded:"A Channel",
disabled:false
},
profile:{
access:"All",
bounded:"Another Channel",
disabled:false,
subCommands:{
bio:{
access:"All",
disabled:true
}
register:{
access:"All",
disabled:false
}
}
Fastforwarding to now, I made a config file that is supposed to edit these commands. The code I wrote works perfectly fine; however, Mongoose is unable to save any of the command's changes. Everything else in my Schema works in the config file except anything related to commands.
I know what the problem. Mongoose can't find the command in the Schema and gets confused somehow. And I know I could fix it by adding all of the commands and their properties to the Schema. The only problem with that is it's tedious and is not a clean solution to me adding any new commands. Plus, I have all of the information for the commands in a separate file, so I don't want to rewrite what I already wrote.
My question is: is there a workaround to my problem? I tried setting commands to Schema.Types.Mixed, but that didn't fix it. I also searched all around for something similar but could not find anything.
Here is the full Schema as requested:
const {Schema, model} = require("mongoose");
const settings = require("../utils/settings");
const guildSchema = Schema({
guildId:String,
symbols:{
prefix:{type:String, default:";"},
currency:{type:String, default:"$"}
},
channels:{
casinoChannels:Array,
fineChannels:Array
},
commands:Schema.Types.Mixed,
hierarchy:[{
name:String,
role:{type:String, default:""},
members:Array
}],
users:[{
userId:String,
cash:Number,
bank:Number,
items:[{
name:String,
amount:Number
}],
timers:{
work:String,
crime:String,
hack:String,
steal:String,
daily:String,
weekly:String,
marry:String,
divorce:String,
idea:String,
report:String,
quiz:String
},
fine:{
fineId:String,
description:String,
report:String,
pay:Number
},
used:String
}],
});
guildSchema.virtual("addUser").set(function(id){
const user = {
userId:id,
cash:settings.cash,
bank:settings.bank
};
this.users.push(user);
return user;
});
module.exports = model("Servers", guildSchema);
Use findOneAndUpdateto update the existing document in the collection.
let the object that you want to update in "commands" in mongodb be in x variable.
Guild.findOneAndUpdate({guildId : serverId},{commands : x));
The object which you have stored in x variable will directly be updated/replaced with this new data when a match is found.
UPDATE TO NOT COMPLETELY REPLACE EXISTING OBJECT
let guild = Guild.findOne({guildId : serverId});
if(guild){
// guild.commands here will have the existing object.
// Modify it as required and then use findOneAndUpdate again
}
The solution is quite simple. I took it from this site: https://mongoosejs.com/docs/2.7.x/docs/schematypes.html
To give credit:
Since it is a schema-less type, you can change the value to anything else you like, but Mongoose loses the ability to auto detect/save
those changes. To "tell" Mongoose that the value of a Mixed type has
changed, call the .markModified(path) method of the document passing
the path to the Mixed type you just changed.
So, whenever I update the commands (aka whenever I change the access, bounded, or disabled variables), I would use the mark modified method on the command function. My code is:
guildSchema.virtual("saveCommands").set(function(name){
if(["access", "bounded", "disabled"].includes(name)) this.markModified('commands');
});

Pulling Out Value from Within Two-Levels Deep Object

I am trying to retrieve one particular value from within a two-levels deep object data structure. First off, though, I am saving into a variable within the function, like this:
getTargetId() {
if (this.authenticationService.isAuthenticated()) {
const userInfo = sessionStorage.getItem('currentUser');
console.log(userInfo);
}
}
From:
console.log(userInfo);
I get this back in the console:
{"token":"sometoken.value","data":{"_id":"8cd0362c0", "phone":"555-4343"...}
What I want to do is specifically pull out the "_id" value here.
I tried:
console.log(userInfo.data._id);
But then my IDE is showing me an error:
'Property '_id' does not exist on type 'string'.
How do I dig out "_id" in this case?
You are accessing it wrong
Try userInfo.data._id
In the log of your object you can see by the {} notation that data is another object, so after accessing data you can access its properties just as you would with any other object.
I also see that you are getting
'Property '_id' does not exist on type 'string'.
This could mean that you never parsed the information. To find out if this is the case this should be right:
Running->
console.log(userInfo);
Returns->
{"token":"sometoken.value","data":{"_id":"8cd0362c0", "phone":"555-4343"...}
Just after this code:
Running->
console.log(typeof userInfo);
Returns->
"string"
With your edits, I can see that this is the case.
Try:
userInfo = JSON.parse(sessionStorage.getItem('currentUser') );
console.log(userInfo.data._id);
The _id property is under the data key:
const response = {
"token":"sometoken.value",
"data": {
"_id":"8cd0362c0",
"phone":"555-4343"
}
};
console.log(response.data._id)
You can also use destructuring:
const { _id } = response.data;
console.log(_id)
or:
const { data: { _id }} = response;
console.log(_id);
So, as #jonsharpe pointed out, the key was to JSON.parse the string first. So this gets me the value I need for "_id":
getTargetId() {
if (this.authenticationService.isAuthenticated()) {
const userInfo = JSON.parse(sessionStorage.getItem('currentUser'));
console.log(userInfo.data._id);
}
}
Actually your string is returned as JSON string. So you have to parse it into object using JSON.parse() if you are using js or with $.parseJSON() if you are using Jquery. So your updated code now looks like this.
var user ='{"token":"sometoken.value","data":{"_id":"8cd0362c0", "phone":"555-4343"}}';
var k = JSON.parse(user);
alert(k.data._id);
And Fiddle is here.
Thank You

For Loop not working inside Node.js while using mongoose

I am trying fetch records from mongoDB through mongoose
router.route('/testaa')
.get(function(req,res){
fisSite.find(function(err, retVal) {
var x = [];
for(var i =0;i<retVal.length;i++){
x.push(retVal[i].site);
}
res.json(x)
});
})
The above code is giving undefined values.
undefined
undefined
undefined
.....
Please help to run the for loop inside node.js so that i can use extract data from array.
Currently what you are doing is you are getting all the document fields and then using only one from it. You can optimize the query using select method which will only retrieve particular field only rather than all fields :
[Note : id field is added by default, hence to remove it in select we specifically mention it using -_id. You can remove -_id if you want to maintain ID inside the response document.]
fisSite.find({}).select('site -_id').exec(function(err, docs)){
if(err){
return res.json({ status : false, message : 'Error Occured.'} );
}
else if(!docs){
return res.json({ status : false, message : 'No documents found.'} );
}
else{
return res.json({ status : success, message : 'Documents found.', data : docs} );
}
}
Imagine you have 10 fields in each document and find results 100 documents, you only need site field from those 100 documents,however unnecessarily you are calling remaining 900 fields.
I have used Lean.exec within Mongoose.
router.route('/site')
.get(function(req,res){
fisSite.find().lean().exec(function(err, retVal) {
var x = [];
for(var i =0;i<retVal.length;i++){
x.push(retVal[i].site);
}
res.json(x)
})
});
Try to add an empty search query to select all documents
Try to change
From this:
fisSite.find(function(err, retVal)
To this:
fisSite.find({}, function(err, retVal)
Also try to do a console.log(retVal) to check if your find actually returns any values.

Neo4j + nodejs: create node using javascript object literal

can't find whether this has been asked before or not, so bear with me.
I'm just starting to use Neo4j with a nodejs backend and the neo4j-driver driver. I wonder if it's possible to create a node with several properties without enumerating each one in the second argument to the session.run method.
app.post("/signup", function(req, res) {
var user = req.body; //{userId: "johnsmith", email: "john#smith.com", ...}
session.run("CREATE (u:User {u}) RETURN u", user).then(function(response) {
/*do stuff with newly created user*/
}, function() {
//handle error
});
});
Currently, this yields the following error: {code: 'Neo.ClientError.Statement.ParameterMissing', message: 'Expected a parameter named u' }, and if I change the above to:
app.post("/signup", function(req, res) {
var user = req.body; //{userId: "johnsmith", email: "john#smith.com", ...}
session.run("CREATE (u:User {u}) RETURN u", {u: user}).then(function(response) {
/*do stuff with newly created user*/
}, function() {
//handle error
});
});
then the error reads: { code: 'Neo.ClientError.Statement.TypeError', message: 'Property values can only be of primitive types or arrays thereof' }.
This doesn't make much sense to me, given that the refcard clearly states you can create a node using a map, like so: CREATE (n {map}); so I must obviously be getting something wrong. I hope I don't have to enumerate all a user's properties like so:
session.run("CREATE (u:User {userId: {u.userId}, email: {u.email}, ...}) RETURN u", {u: user}).then(/*...*/)
Thanks in advance
Map could not be the value of the properties
You can set properties using a parameter - http://neo4j.com/docs/developer-manual/current/cypher/clauses/set/#set-set-all-properties-using-a-parameter
So you need to check the input parameter and transform its properties if necessary.
For example:
app.post("/signup", function(req, res) {
var params = {};
//{userId: "johnsmith", email: "john#smith.com", ...}
Object.keys(req.body).forEach( function(k) {
var value = req.body[k];
if (!isPrimitive(val)) value = JSON.stringify(value);
params[k] = value;
});
session.run("CREATE (u:User) SET u = {user} RETURN u", {user: params})
.then(function(response) {
// do stuff with newly created user
}, function() {
// handle error
});
});
Where isPrimitive an abstract function that checks whether a variable is a primitive.
Neo4j only supports storing specific kinds of data structures to a property. To quote from the Cypher Refcard:
Neo4j properties can be strings, numbers, booleans or arrays thereof.
And, to be more exact, in order for an array (or "collection") to be stored as a property value, all its elements must be of the same primitive type.
The answer from #stdob-- provides one possible simple workaround to this (but it stringifies all arrays, even ones that can be stored without conversion).
NOTE: The refacrd needs to be a bit more clear. Nested maps are supported, in general. For instance, you can freely pass in JSON data as Cypher query parameters. However, maps containing nested maps are NOT supported for storing as property values.

How to return array of IDs with Mongoose find? [duplicate]

I have a problem where I want to be able to get all the unique cities for a collection, and my code looks something like this:
var mongoose = require("mongoose"),
Schema = mongoose.Schema;
var PersonSchema = new Schema({
name: String,
born_in_city: String
});
var Person = mongoose.model('Person', PersonSchema);
In native MongoDb I could just do db.person.distinct("born_in_city"), but there doesn't seem to be anything equivalent for Mongoose. Is the only option to iterate over all of the documents myself to do this, or is there a better solution?
In an attempt to use the underlying node-mongodb-native as suggested by the answerer I attempted to do this:
mongoose.connection.db.collections(function(err, collections){
collections[0].distinct('born_in_city', function( err, results ){
console.log( err, results );
});
});
However the results is empty and there's no error. I would also prefer to be able to fetch only the needed collection by name rather than have to filter what collections return if at all possible.
Just to give an update for Mongoose 3.x:
MyModel.find().distinct('_id', function(error, ids) {
// ids is an array of all ObjectIds
});
In my program, this code works.
Person.collection.distinct("born_in_city", function(error, results){
console.log(results);
});
by
node.js v0.4.7,
mongoose 1.3.3
I read through the source code and the node-mongodb-native driver is what powers the class. So on the connection object. So after you have done mongoose.connect(mongodb://), you can give this a shot.
if(mongoose.connections.length > 0) {
var nativeconn = mongoose.connections[0].conn;
nativeconn.person.distinct('born_in_city', function(error, results){
});
}
const findBornCity = async() => {
const bornCity = await Person.find().distinct("born_in_city")
return bornCity
}

Categories

Resources