I can't access sub sub documents I want to query the sub documents implement back end pagination so that I can render them in a separate page
I've tried using dot notation something.something.something and even using this ["something"]["something"]["something"] arrays since I recently found out objects are kind of arrays
This is the model Schema || the child Schema
const modelSchema = new mongoose.Schema({
modelname: {
type: String,
required: true,
minlength: 5,
maxlength: 250
}
});
This is the Bikes Schema || parent Schema
const bikeSchema = new mongoose.Schema({
make: {
type: makeSchema,
required: true
}
})
This is how data is stored in Mongodb
"_id" : ObjectId("5d5e13e8edcbbf038c1f9b8e"),
"make" : {
"_id" : ObjectId("5d40f0b40268d80ac8c30973"),
"makename" : "{ _id: 5d40f0b40268d80ac8c30973, makename: 'ducatii', __v: 0 }"
}
The expected output according to the documentation in order to query the makename ducatii is to do something like this
console.log(bikes[0]["make"]["makename"]["makename"])
or this
console.log(bikes[0].make.makename.makename)
To embedded document into a document you have to do this like the below
var childSchema = new Schema({ name: 'string' });
var parentSchema = new Schema({
// Array of subdocuments
children: [childSchema],
// Single nested subdocuments. Caveat: single nested subdocs only work
// in mongoose >= 4.2.0
child: childSchema
});
Your case
const modelSchema = new mongoose.Schema({
makename: {
type: String,
required: true,
minlength: 5,
maxlength: 250
}
});
const bikeSchema = new mongoose.Schema({
make: {
makename: modelSchema
}
})
then you can access it like
console.log(bikes[0]["make"]["makename"]["makename"])
Two things to note:
If the returned result is a MongoDB cursor object, then you can't access via an array index. You'll need to retrieve the item from the cursor using the appropriate method.
Your first makename field points to a JSON string, not an object. You cannot access the nested makename.makename from a JSON string. You must first decode the JSON into an object before accessing the nested property.
This seems to be an issue with how you are storing your sub documents.
For example:
bikes[0].make.makename is actually a string, not a valid object. You won't be able to JSON.parse this string either, because you would have to wrap each key/value with escaped double quotes.
If you are able to store this sub-document correctly, then you should be good to use the object in the way you expect!
Related
I am using MongoDB, Mongoose, Node.js and express. I am trying to access a specific element of a field within a document where the field happens to be an array. I have looked at the MongoDB documentation on projection and dot notation. I have also looked at various sites like Geeks for Geeks and Tutorials Point but after experimenting cannot seem to get the right syntax. Here is my model:
const mongoose = require('mongoose')
const Schema = mongoose.Schema;
const QuestionSchema = new Schema ({
userid: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: false
},
title: String,
keyword1: String,
keyword2: String,
keyword3: String,
body: String,
upvotes: {
type: Number,
default: 0
},
datePosted: {
type: Date,
default: new Date()
},
answers: [{
myUUID: mongoose.Schema.Types.ObjectId,
respondentID: Number,
respondent: String,
text: String,
date: Date,
upvotes: Number
}]
});
const Question = mongoose.model('Question', QuestionSchema);
module.exports = Question
Ultimately, I am specifically trying to access all the various "text" elements of the "answers" array. I thought I would get the question first. Then get the array. Then iterate through the array and access and display each "text" element for each "array". Here are my mongoose queries:
const Question = require('../models/Question')
module.exports = async (req,res) =>{
console.log("You are inside displayAnswers!")
const thisQuestionID = req.body.questionID;
console.log(thisQuestionID);
const thisQuestion = await Question.find({"_id" : thisQuestionID}).populate('userid');
console.log(thisQuestion)
const answers = thisQuestion.answers;
console.log(answers)
res.render('displayAnswers', {
answers
})
}
I can tell from the console log output that I am in fact getting the correct 'question' document. I 'thought' that once I had that, that I could just use dot notation to get all the answers as a List (see const answers above) and then I could access each element of that List using the index. But I cannot even seem to get the 'answers' array here. Any thoughts or point me in the right direction?
Allora, I'm using mongoose for the first time and I decided to create 2 schemes: the first one represents a user and the second one represents his enquires. Users have an array of enquires like:
var userSchema = new mongoose.Schema({
name: String,
enquires: { type : [Enquire.schema] , "default" : [] },
});
var enquireSchema = new mongoose.Schema({
status: {type: String, 'default': 'pending'},
enquire: String,
});
I see that if I search for an enquire and update its status, it doesn't update the same enquire on the user's array, meaning that they are different object. I don't want to save an array of IDs as it will be the same as a relational database, so I see only 1 solution which is forgetting about the enquire scheme and use only the User scheme. Is it the way mongoose works? For every relationship do I have to insert everything like nested object?
I think you should use references to achieve what you want to achieve.
For more information on mongoose references and populate see Mongoose Populate documentation.
Try this, It may help you.
User Schema :
var userSchema = new mongoose.Schema({
name: String,
enquires: [{ type : mongoose.Schema.Types.ObjectId , ref : 'Enquiry' }]//array of enquiries
});
var User = mongoose.model('User',userSchema );
module.exports = User;
Enquiry Schema :
var enquireSchema = new mongoose.Schema({
status: {type: String, 'default': 'pending'},
enquire: String,
});
var Enquiry = mongoose.model('Enquiry',enquireSchema );
module.exports = Enquiry ;
Working :
create a new Enquiry.
Push it's ID(_id) into user's enquires array.
var enquiry = new Enquiry();
enquiry.enquire = "Dummy enquiry";//set the enquiry
enquiry.save(function(err,result){
if(!err){
//push 'result._id' into users enquires array
}
});
whenever you update an enquiry, it will be automatically updated in
user's document.
use populate to retrieve user's enquiries.
You can embed sub documents (entity) which has id and is like a document or embed native array like a normal property.
And I think the correct definition for yours is :
var enquireSchema = new mongoose.Schema({
status: {type: String, 'default': 'pending'},
enquire: String,
});
var userSchema = new mongoose.Schema({
name: String,
enquires: { type : [enquireSchema] , "default" : [] },
});
If you use refs in embedded link then there are two separate collections and be like relational db's.
Short and clear: is there any way to prevent setting a schema field but allowing to get the value?
I've been around the Mongoose Documentation but can't find what I'm looking for.
An alternative if you want to set a default value that can never be changed:
var schema = new Schema({
securedField: {
type: String,
default: 'Forever',
set: function (val) { return this.securedField; }
});
Define the field as a virtual getter instead of a traditional field.
For example, say you wanted to make the pop field of your collection read-only when accessed via Mongoose:
var schema = new Schema({
city: String,
state: String
});
schema.virtual('pop').get(function() {
return this._doc.pop;
});
By accessing the private _doc member of your model instance it's possible this may break in the future, but this worked fine when I tested it just now.
Since mongoose 5.6 you can do: immutable: true
var schema = new Schema({
securedField: {
type: String,
default: 'Forever',
immutable: true
}
});
You can just return from set the same value as the default value, no need to reference the _this document:
var schema = new Schema({
securedField: {
type: String,
default: 'Forever',
set: () => 'Forever'
});
I have two Mongoose schemas, User and Code. Each user can have many codes.
user.js:
var mongoose = require('mongoose');
var codeSchema = require('./code');
var userSchema = mongoose.Schema({
google: {
id: String,
token: String,
email: String,
name: String
},
codes: [codeSchema]
}, {collection : 'users'});
code.js:
var mongoose = require('mongoose');
var codeSchema = mongoose.Schema({
code: String,
name: String,
link: String
}, {collection: 'codes'});
module.exports = codeSchema;
My problem is, whenever I access a user's array of codes by user.codes, I get something like { _id: 56c4c82a37273dc2b756a0ce },{ _id: 56c4c82a37273dc2b756a0cd } rather than the JSON for a code.
What am I missing?
You're missing populate.
By default, Mongoose will only give you the _ids of any references made in a document. populate allows you to fill out nested documents.
userSchema.findOne({}).populate('codes');
More here
please check that you are inserting other values or not this can be a case . Please write how you are inserting in array . I have two other way check out
There are two way to do this
1-->either you save refrence id of codeschema and
2--> is you can insert whole codeschema in array
1. codes: {
type: mongooseSchema.ObjectId,
ref: 'codeSchema',
required: true
},
and when all data is in array 56c4c82a37273dc2b756a0ce,56c4c82a37273dc2b756a0cd
that can be done by this query
domain.User.update({_id:id}
,{$addToSet:{code:codeObjvalue}},
function(err,res){});
and then populate them by this
domain.users.find({},'code')
.populate('code','code color email').
exec(function(err,results){
callback(err, results);
});
2-- and second is to insert whole code schema in userschema
create a codeschema object and add in set like this
var codeobj={};
codeobj.code="xyz";
codeobj.email="xyz#gmail.com"
var codeobject = new domain.code(codeobj);
domain.User.update({_id:id},{$addToSet:{code:codeobject}},function(err,user1){
});
Woops, turns out I was using the wrong dataset, not adding the codes properly (facepalm). Thanks to everyone who answered!
I am struggling to insert a document inside another document. I've looked at all the entries like this but they aren't quite what I am looking for.
Here is the scenario:
I have a common document that has its own schema. Lets call it a related record:
(function(){
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var relatedRecordSchema = new Schema({
params: {
recordId: Schema.Types.ObjectId,
recordType: String,
recordTitle: String
},
metadata: {
dateCreated: {type: Date, default: Date.now}
}
},{ _id : false });
mongoose.model('RelatedRecord', relatedRecordSchema);
})();
I have no trouble inserting this in an ARRAY inside document that require it. I.e its configured this way:
//Embedded
relationships: {
following: [mongoose.model('RelatedRecord').schema],
followers: [mongoose.model('RelatedRecord').schema],
blocked: [mongoose.model('RelatedRecord').schema]
}
This works perfectly.
The scenario that does not work is where there is a single related record, lets say the source of a notification:
var notificationSchema = new Schema({
params: {
title: String,
imageUrl: String,
source: mongoose.model('RelatedRecord').schema
},
metadata: {
dateCreated: { type: Date, default: Date.now },
dateViewed: Date
}
});
So when I am creating the notification I try and assign the previously prepared RelatedRecord
returnObj.params.source = relatedRecord;
The record appears during a debug to be inserted (it is inside a _docs branch but far deeper than I would expect) but when the object is saved (returnObj.save()) the save routine is abandoned without error, meaning it does not enter into the callback at all.
So it looks to me that i'm confusing mongoose as the dot assignment is forcing the subdoc into the wrong location.
So the question is simple:
How do I set that subdocument?
What the question isn't:
No I don't want to populate or advice on how you would solve this problem differently. We have sensible reasons for doing things how we are doing them.
Cheers
b
As Hiren S correctly pointed out:
1) Sub-Docs = array, always. Its in the first line in the docs :|
2) By setting the type to mixed, assignment of the object worked.
I'm a dumdum.