i was using mongoose in my project with typescript when i add virtual called subdomains to populate the data from another collection its working without error but i can't print the populated data directly, i can only access the value using console.log((r as any).subdomains) but when print the console.log(r as any) there is no field called subdomains,please check example 1 and example 2
export interface IDomain{
domain:string
owner:Schema.Types.ObjectId,
}
const domainSchema = new Schema<IDomain>({
domain:{type:String,required:true},
owner:{type:Schema.Types.ObjectId,required:true},
})
domainSchema.virtual("subdomains",{
ref:"DomainMonitor",
localField: '_id',
foreignField: 'owner'})
Querying the database | example 1
Domain.findOne({owner:"633ebe32d0733c0a8eb4f8d6"}).populate("subdomains").then(r=>{
console.log(domains)
})
output | example 1
{
_id: new ObjectId("6342fa2d4b730f004704eb45"),
domain: 'dummy.com',
__v: 0,
owner: new ObjectId("633ebe32d0733c0a8eb4f8d6")
}
Query the database | example 2
Domain.findOne({owner:"633ebe32d0733c0a8eb4f8d6"}).populate("subdomains").then(r=>{
const domains= (r as any).subdomains
console.log(domains)
})
output | example 2
[{
_id: new ObjectId("6342fa314b730f004704eb47"),
owner: new ObjectId("6342fa2d4b730f004704eb45"),
subdomain: [
'dummy',
],
wildcard: [ '*.dummy.com', '*.dummy.com' ],
__v: 1
}]
Another approach where you represent your schema as object, not as JSON (using .-operator) is the following:
// create a new schema
const MessageSchema = new mongoose.Schema(
{
channel: { type: String },
content: { type: String, required: true },
moderator: { type: Number },
},
// Add this to your Schema
{
toObject: { virtuals: true },
// alternatively: toJSON: { virtuals: true}, if you want your output as json
}
);
// Approach 2:
const mySchema = new mongoose.Schema({
domain: { type:String, required:true },
owner: { type:Schema.Types.ObjectId, required:true }
});
mySchema.set('toObject', { virtuals: true })
Mongoose Documentation says:
Keep in mind that virtuals are not included in toJSON() and toObject() output by default. If you want populate virtuals to show up when using functions like Express' res.json() function or console.log(), set the virtuals: true option on your schema's toJSON and toObject() options.
The reason is stated in the mongoose documentation (https://mongoosejs.com/docs/guide.html):
If you use toJSON() or toObject() mongoose will not include virtuals by default. This includes the output of calling JSON.stringify() on a Mongoose document, because JSON.stringify() calls toJSON(). Pass { virtuals: true } to either toObject() or toJSON().
Basically your console.log statement makes a call to toJSON and does not include virtuals by default.
You can include the following in your schema definition in order to include virtuals in your toJSON calls:
domainSchema.set('toJSON', { virtuals: true });
Related
I have two schemas as the following:
const castListSchema = new Schema({
id: String,
roleInVideo: String
});
const videoSchema = new Schame({
castList: { type: [castListSchema], default: [] }
});
I want to get data by the following structure:
castList: [
{
details: { ... },
roleInVideo: 'director'
},
...
]
I want to use virtual not aggregate and etc...
Is it possible? How?
Yes, you can use the virtual function inside the array of objects.
Use the following code to use the virtual function for the array of objects.
videoSchema.virtual("castList.castData", {
ref: "new_assets",
localField: "castList.castListSchema",
foreignField: "_id",
justOne: true
});
In populate also use this "castList.castData" as key to retrieve the data.
I'm having some issues using the Mongoose queries. I'm just trying to find documents in a collection using the where clause.
Unfortunately, it seems you can't use the where clause on populated documents.
This is the collection schema
const schema: Schema = new Schema({
game: { type: Schema.Types.ObjectId, ref: 'Game', required: true, index: true },
players: [{ type: Schema.Types.ObjectId, ref: 'Player', required: true, index: true }],
scores: [{ type: String }],
resultDate: { type: Date}
});
I'm trying to find all games where type = 1v1, so I tried this
let query = Matchs.find()
.populate('game')
.populate('players')
.where('game.name').equals('Trackmania')
const matchs: Match[] = await query.exec();
This returns an empty array.
Notes
Removing the where clause returns the correct results (all Matchs)
Any where clause on game returns an empty array
I'd like to use query builder instead of passing a json because I use some parameters to define what I am querying
I read that where clause didn't work on nested documents, but there must be a way to do this right ? Am I missing something ?
You can Use Lookup and Match instead of Where.
MatchesModel.aggregate([
const GameName = req.query;
{"$lookup":{
"from":"games", // name of the foreign collection
"localField":"game",
"foreignField":"_id",
"as":"game"
}},
{"$lookup":{
"from":"players",
"localField":"players",
"foreignField":"_id",
"as":"players"
}},
{"$match":{
"game.name":{
"$eq": GameName
}
}}
])
schema:
const mongoose = require ('mongoose');
const workSchema = new mongoose.Schema ({
role: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Staff_roles'
},
movie: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Movie'
}
})
const staffSchema = new mongoose.Schema ({
name: {
type: String,
required: true,
},
works : [workSchema],
summary: {
type: String
}
});
module.exports = mongoose.model ('Staff', staffSchema)
I need to implement this in a different page for movies where I need to show the properties of the fields inside "works".
Works is shown as a normal object with the embedded document displaying correctly when using findById() but it only shows [object] for works when using find().
I need to run the find query as Staff.find({ "works.movies._id" :movie.id }) later on so I need to use find later on and it keeps returning it as [object] which makes it impossible to access the contents of work later on the .ejs file for it.
I already tried populating it with 'works' but that doesn't do anything.
staff router code and result using console logs when using findById():
const staff = await Staff.findById(req.params.id).populate('works.movie works.role').exec()
console.log (staff)
{
_id: new ObjectId("61850be2d9272be145267f4d"),
name: 'hideo',
works: [
{
role: [Object],
movie: [Object],
_id: new ObjectId("61850be9d9272be145267f55")
}
],
__v: 0
}
staff router code and result using console logs when using find():
const staff = await Staff.find({id:req.params.id}).populate('works.movie works.role').exec()
console.log (staff)
[
{
_id: new ObjectId("61850be2d9272be145267f4d"),
name: 'hideo',
works: [ [Object] ],
__v: 0
}
]
I am new to MangoDB and Node JS. I have always worked on SQL databases and I do not know the syntax of MongoDB well. I wanna try to filter the array that I receive from a MongoDB database. I know that JavaScript has a .filter() function to filter just the results that contain a string. Is it best practice to get all the objects from MongoDB and filter in Node or do I let MongoDB do the filtering?
My Node.JS project is a back-end project using Node.JS and Express to do CRUD operations on a MongoDB database. In the request I send a parameter called 'equalTo' that contains the value that should be filtered on.
var router = express.Router();
var Plot = require("./models/plot");
...
router.get("/plots", (req, res) => {
let query = "" + req.query.equalTo;
Plot.find((err, plots) => {
if (err) {
res.send(err);
}
res.json(plots);
});
});
The filtering should be an OR filter where all results where either the name or the cropName should CONTAIN the value of the string. If it is possible I would also like the comparison to ignore uppercase's. Here is a schema for the Plot object:
const plotSchema = mongoose.Schema({
area: {
type: String,
required: true
},
comments: {
type: String,
required: true
},
cropGroupName: {
type: String,
required: true
},
cropName: {
type: String,
required: true
},
name: {
type: String,
required: true
},
plotId: {
type: Number,
required: true
},
coords: {
type: [],
required: true
},
}, {
collection: "plots"
});
The format is the following:
Plot.find({$or:[{name: "anyname"},{cropName:"othername"}]})
For further information you can read here https://docs.mongodb.com/manual/reference/operator/query/or/
You may replace the strings above in your case with equalTo.
I'm trying to do some models in mongoDB using mongoose as a schemaless during working saving data works fine but when i try to fetch the data there is problem
this is the Model Creation code :
const TemplateSchema = new Schema({
any: {},
blog: {
type: Schema.Types.ObjectId,
ref:'blogs'
},
user:{
type: Schema.Types.ObjectId,
ref:'users'
},
date:{
type: Date,
default: Date.now
}
},{ strict: false });
Saving Code :
let newTemplate = {
tempbody: { name: 'Laith', age: 26 },
blog: blog.id,
user: req.session.userid,
}
//console.log(inputObject);
new Template(newTemplate).save()
.then((template) => {
res.redirect(`/blogs/posts/${req.params.blogid}`);
});
Fetching Code :
Template.findOne({_id: req.params.templateid}).populate('blog').then(template =>{//To Fetch ObjectID for Blog from DB
if(template && template.blog.blogID == req.params.blogid) {
console.log(template.tempbody);
res.render('blogs/addPostTemplate', {
template: template,
blogid: req.params.blogid,
templateid: req.params.templateid
});
} else {
res.redirect(`/blogs/posts/${req.params.blogid}`);
}
});
The result suppose to be :
The Object tempbody but it gives always undefined
and if i try to fetch template._id it works fine
and if i print template as full object it also gives the result
and sometimes gives : (node:16840) [DEP0079] DeprecationWarning: Custom inspection function on Objects via .inspect() is deprecated
Any help is appreciated.