Retrieve value from parent in MongoDB sub-document - javascript

I have two schemas
childrenSchema = new Schema({
name: String
});
parentSchema = new Schema({
type: String,
children: [childrenSchema]
});
Now I want a method in childrenSchema from which I retrieve the type of the parent. I guess it is something like
childrenSchema.methods.generateName = () => {
// get parent type
};
Do there exist a function like this.parent().type, i.e.
childrenSchema.methods.generateName = () => {
// get parent type
return this.parent().type;
};

You can do like this :
childrenSchema = new Schema({
name: String
});
childrenSchema.methods.generateName = () => {
// get parent type
return this.ownerDocument().type;
};
parentSchema = new Schema({
type: String,
children: [childrenSchema]
});
var childModel = mongoose.model('Children', childrenSchema);
var parentModel = mongoose.model('Parent', parentSchema);
var parent = new parentModel({type: 'Scifi'});
parent.children.push(new childModel({name: 'Star wars'}));
parent.save(function(err, doc){
console.log(doc.children[0].generateName()); // Scifi
});

Related

expected undefined to equal 'String'

I am new to JS and I am trying to create a model with Mongoose but I get the following error: expected undefined to equal 'String' from the test system.
This is my code to create the model:
`
// CREATE MODEL: Album
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const model = mongoose.model;
const albumSchema = new Schema({
performer: {
type: String,
required: true
},
title: {
type: String,
required: true
},
cost: {
type: Number,
required: true,
},
});
const Album = model('Album', albumSchema)
// REMEMBER TO EXPORT YOUR MODEL:
module.exports = Album
`
This is the code of the tests:
const createdModels = Object.keys(mongoose.models);
describe('"Album" model', function () {
it("should be declared", function () {
expect(mongoose.models.Album).to.exist;
});
describe("should contain fields:", function () {
const albumModel = mongoose.models.Album;
const albumSchema = albumModel ? mongoose.models.Album.schema.obj : [];
it("performer: String", function () {
expect(albumSchema["performer"]).to.exist;
expect(albumSchema["performer"].name).to.equal("String");
});
it("title: String", function () {
expect(albumSchema["title"]).to.exist;
expect(albumSchema["title"].name).to.equal("String");
});
it("cost: Number", function () {
expect(albumSchema["cost"]).to.exist;
expect(albumSchema["cost"].name).to.equal("Number");
});
});
});

Mongoose Schema method: Error - model method is not a function

I have two Mongoose model schemas as follows. The LabReport model contains an array of the referenced SoilLab model. There is a static method in the SoilLab model that I was using to select which fields to display when LabReport is retrieved.
//LabReport.js
var mongoose = require("mongoose");
var SoilLab = mongoose.model("SoilLab");
var LabReportSchema = new mongoose.Schema(
{
labFarm: { type: mongoose.Schema.Types.ObjectId, ref: "Farm" },
testName: { type: String },
soilLabs: [{ type: mongoose.Schema.Types.ObjectId, ref: "SoilLab" }],
},
{ timestamps: true, usePushEach: true }
);
LabReportSchema.methods.toLabToJSON = function () {
return {
labReport_id: this._id,
testName: this.testName,
soilLabs: this.soilLabs.SoilToLabJSON(),
};
};
mongoose.model("LabReport", LabReportSchema);
//SoilLab.js
var mongoose = require("mongoose");
var SoilLabSchema = new mongoose.Schema(
{
description: { type: String },
sampleDate: { type: Date },
source: { type: String },
},
{ timestamps: true, usePushEach: true }
);
SoilLabSchema.methods.SoilToLabJSON = function () {
return {
description: this.description,
sampleDate: this.sampleDate,
source: this.source,
};
};
mongoose.model("SoilLab", SoilLabSchema);
When I try to retrieve the LabReport, I get "this.soilLabs.SoilToLabJSON is not a function". This is how I'm trying to retrieve LabReport.
//labReports.js
...
return Promise.all([
LabReport.find()
.populate("soilLabs")
.exec(),
LabReport.count(query).exec(),
req.payload ? User.findById(req.payload.id) : null,
]).then(function (results) {
var labReports = results[0];
var labReportsCount = results[1];
var user = results[2];
return res.json({
labReports: labReports.map(function (labReport) {
return labReport.toLabToJSON(user); //This cant find SoilToLabJSON
}),
If I remove the .SoilToLabJSON in LabReport.js and just call this.soilLabs, it works but outputs all of the soilLabs data which will become an issue when I have the model completed with more data. I have dug into statics vs methods a little and tried changing it to statics but it didn't work.
I get the soilLabs to populate but not sure why the .SoilToLabJSON method is inaccessible at this point. Do I need to find() or populate the soilLab differently? Is the method incorrect?
labReport.toLabToJSON is passing an array and that was causing the error for me. I simply edited the LabReport.js to the following to take the array and map it to SoilToLabJSON properly.
myTestSoilLabOutput = function (soilLabs) {
var test = soilLabs.map(function (soilLab) {
return soilLab.SoilToLabJSON();
});
return test;
Changed the LabReportSchema.methods.toLabToJSON to:
LabReportSchema.methods.toLabToJSON = function () {
return {
labReport_id: this._id,
testName: this.testName,
soilLabs: myTestSoilLabOutput(this.soilLabs),
};
};

model.find({}).populate('place').populate('location') does not return place and location

I have document with the following structure on MongoDb,
I am using Mongoose version ^4.8.1 with my node application. I have created 3 schema models for the above document which are as follows,
Event.js
var mongoose = require('mongoose');
var eventSchema = new mongoose.Schema({
description: {
type: String
},
end_time: {
type: Date
},
start_time: {
type: Date
},
name: {
type: String
},
place: {
type: mongoose.Schema.Types.ObjectId,
ref: 'place'
}
});
eventSchema.index({name: 'text'},{'place.location.country':"text"});
var Event = mongoose.model('events', eventSchema);
module.exports= Event;
Place.js
var mongoose = require('mongoose');
var placeSchema = new mongoose.Schema({
name: {
type: String
},
location: {
type: mongoose.Schema.Types.ObjectId,
ref: 'location'
}
});
var Place = mongoose.model('place', placeSchema);
module.exports= Place;
Location.js
var mongoose = require('mongoose');
var locationSchema = new mongoose.Schema({
city: {
type: String
},
latitude: {
type: String
},
country: {
type: String
},
located_in: {
type: String
},
state: {
type: String
},
street: {
type: String
},
zip: {
type: String
},
});
var Location = mongoose.model('location', locationSchema);
module.exports= Location;
Common handler to access /query database,
dbHandler.js
querandpoplulate : function(model,condition,options)
{
return new Promise(function(resolve, reject) {
options = options||{};
console.log("model is" + model);
model.find({}).populate('place').populate('location').exec(function(error, data) {
if (error)
console.log(error);
reject(error);
console.log(data);
resolve(data);
})
})
}
Here is how i query,
dbHelper.querandpoplulate(mongoose.model('events'), {$text: {$search: searchString},'place.location.country': countryString},function(error,data){
callback(data);
});
Question: it does not return the result set with the place and location , it returns null in place field.
It looks to me like your documents are saved as embedded documents, but not as referenced documents.
To fetch such documents, you don't need to do any population. Simple find query should work for you.
Try this:
model.find({}).exec(function(error, data) {
if (error)
console.log(error);
reject(error);
console.log(data);
resolve(data);
})
As you are not saving the data in the mongoDB but only retrieving it. you need to define the schema that matches with the document structure.
As discussed with you, i think you need to change the Schema, and combine all 3 schemas in one file (Event.js).
var mongoose = require('mongoose');
var locationSchema = new mongoose.Schema({
city: {
type: String
},
//add other fields here
});
var placeSchema = new mongoose.Schema({
name: {
type: String
},
location: locationSchema
});
var eventSchema = new mongoose.Schema({
description: {
type: String
},
//add other fields here too
place: placeSchema
});
eventSchema.index({name: 'text'},{'place.location.country':"text"});
var Event = mongoose.model('events', eventSchema);
module.exports= Event;

In mongoose how to iterate over array of ObjectId?

I try to refactor from javascript object to mongoose object.
I have two simple models:
Candidate model:
var candidateSchema = new Schema({
name: String,
score: { type: Number, default: 0, min: -2, max: 2 }
});
candidateSchema.methods.updateScore = function updateScore(newScore) {
this.score = newScore;
};
Vote model containing a list of candidate:
var voteSchema = new Schema({
candidates: [
{ type: Schema.Types.ObjectId, ref: 'Candidate' }
]
});
function candidateAlreadyExists(candidates, newCandidate) {
var alreadyExists = false;
candidates.forEach(function (candidate) {
if (newCandidate.name === candidate.name) {
alreadyExists = true;
}
});
return alreadyExists;
}
voteSchema.methods.addCandidate = function addCandidate(newCandidate, callback) {
var candidates = this.candidates;
if (!candidateAlreadyExists(candidates, newCandidate)) {
candidates.push(newCandidate);
}
this.save(callback);
};
I try to add a static method in my voteSchema to add a new candidate, only if it doesn't exist.
I can't iterate over my candidates (candidates.forEach(function (candidate) {) because it's an array of _ids and not an array of javascript objects
Someone have an idea ?
It would be better to use $addToSet to let MongoDB do that for you atomically.
voteSchema.methods.addCandidate = function addCandidate(newCandidate, callback) {
this.candidates.addToSet(newCandidate._id);
this.save(callback);
};

Define a function as a default in a field in mongoose

I want to do something like this:
var categorySchema = new Schema({
id: {
unique: true,
default: function() {
//set the last item inserted id + 1 as the current value.
}
},
name: String
});
This is posible?.
var categorySchema = new Schema({
id : {
type : Number
},
name : {
type : String
}
});
// Define a pre-save method for categorySchema
categorySchema.pre('save', function(next) {
var self = this;
// Example of your function where you get the last ID
getLastId(function(id){
// Assigning the id property and calling next() to continue
self.id = id;
next();
});
});

Categories

Resources