GraphQL and MongoDB - "Cast to Array failed" With Array [duplicate] - mongodb

I am trying to create the model for my mongodb database using mongoose. This is what I am trying to do:
var Class = mongoose.model('Class', {className: String, marks: [{type: Number}], grades: [{type: Number}]});
var User = mongoose.model('User', {email: String, classes: [Class] });
//Lets create a new user
var class1 = new Class({className: 'aaa', marks: [72, 88, 63], grades: [30, 40, 30]});
var user1 = new User({email: 'aaa#some.com', classes: [class1]});
Saving class1 seems to work okay but when I check mongodb, this is displayed:
{
"_id" : ObjectId("someId"),
"className" : "TEST1234",
"grades" : [ 30, 40, 30 ],
"marks" : [ 72, 88, 63 ],
"__v" : 0
}
What is "__v : 0"?
Saving the user is not successful at all, this is the following error:
ValidationError: CastError: Cast to Array failed for value "{ marks: [ 72, 88, 63 ],
grades: [ 30, 40, 30 ],
_id: someId,
className: 'TEST1234' }" at path "classes"
`
What exactly does the error mean? Why is it casting anything to a array? Shouldn't classes: [Class] be an array of type class?

Man, I had a similar issue creating an Schema like this:
QuestionnaireSchema = mongoose.Schema({
formId: Number,
name: String,
questions: [
{
type: String,
title: String,
alternatives:[{
label: String,
value: "Mixed"
}]
}
]
});
My mistake was that I am using "type" as a field name and this is reserved word in mongoose.
I just change:
type: String,
to
formType: String,
and that works.
see: https://github.com/Automattic/mongoose/issues/1760

Explicitly defining the type rule on a property called type is allowed and won't throw an error. like this:
type: {type: String}

Try changing the class definition to :
var classSchema = mongoose.Schema({className: String, marks: [{type: Number}], grades: [{type: Number}]});
var userSchema = mongoose.Schema({email: String, classes: [classSchema] });
var User = mongoose.model('User',userSchema);
This is required since mongoose is not able to parse the object without a related schema. Now when you create a new Schema for the internal class object and refer it in the main userSchema mongoose should be able to parse your object.

Your model definition is incorrect, you should fix like below.
// var Schema = mongoose.Schema;
var User = mongoose.model('User',{
email: String,
classes: [ {type: Schema.Types.ObjectID, ref: 'Class'}]
});
var Class1 = new Class({/*yourDataWillBeHere*/})
Class1.save(function(err, classData) {
var User1 = new User({/*YourDataWillBeHere*/})
User1.classes.push(classData._id);
User1.save(function(err, userData) {
//make something with userData object
})
})
Then you can get fetched data using with populate() like this
User
.find()
.populate('classes')
.exec()

By default, if you have an object with key 'type' in your schema, mongoose will interpret it as a type declaration.
// Mongoose interprets this as 'loc is a String'
var schema = new Schema({ loc: { type: String, coordinates: [Number] } });
Changing the typeKey:
var schema = new Schema({
// Mongoose interpets this as 'loc is an object with 2 keys, type and coordinates'
loc: { type: String, coordinates: [Number] },
// Mongoose interprets this as 'name is a String'
name: { $type: String }
}, { typeKey: '$type' }); // A '$type' key means this object is a type declaration
Link: http://mongoosejs.com/docs/guide.html#typeKey

Just for Update
Now Mongoose supports subdocuments, which are the documented way to nest arrays,
var arraySchema = new Schema({
property: String
});
var objectSchema = new Schema({
arrays: [arraySchema]
});
Sources
http://mongoosejs.com/docs/schematypes.html

I got a similar issue using mongoose 5.7.0+ using double nested schema.
Except it wasn't related to the keyword type but a mongoose validation bug.
https://github.com/Automattic/mongoose/issues/8472
Temporary workaround: Use Schema.Types.Mixed for the subschema

Related

Cannot access some properties from Mongoose document

I am doing a query on my database using Mongoose to retrieve all documents in a collection. Currently there is only one document in the collection. It returns the document and looks fine, but I cannot access some of the properties.
Code snippet:
User.find()
.then((response)=>{
console.log(response);
console.log();
console.log(response[0]._id);
console.log(response[0].name);
console.log(response[0].email);
console.log(response[0].zipCode);
console.log(response[0].dateTime);
console.log(response[0].ipAddr);
console.log(response[0].pageVisited);
}).catch((err)=>{console.log(err)});
Result:
[
{
_id: 5f6d4dc312c76000170c5c43,
name: 'Bob',
email: 'bob#mail.com',
zipCode: '12345',
pageVisited: 'p1m2549',
dateTime: 2020-09-25T01:54:11.152Z,
ipAddr: '111.111.111.111',
__v: 0
}
]
5f6d4dc312c76000170c5c43
Bob
bob#mail.com
undefined
undefined
undefined
undefined
What could be causing this bizarre behavior? It really doesn't make any sense that I can access some of the properties but not others.
That could be because these elements not be defined in the Schema
Define Schema as mentioned below
var Schema = mongoose.Schema;
var UserSchema = new Schema({
name: String,
email: String,
zipCode: String,
pageVisited: String,
dateTime: Date,
ipAddr: String,
__v: Number
});
var User = mongoose.model('users', UserSchema );
User.find()
.then((response)=>{
console.log(response);
console.log();
console.log(response[0]._id);
console.log(response[0].name);
console.log(response[0].email);
console.log(response[0].zipCode);
console.log(response[0].dateTime);
console.log(response[0].ipAddr);
console.log(response[0].pageVisited);
console.log(response[0].__v);
}).catch((err)=>{console.log(err)});

mongoose schema declare with array of different nested schemas

I want to know whether my below schema definition for PersonSchema will work or not. Is it possible to declare a schema type like my example?
I mean, I want my PersonSchema to be an Array of type EmployedPersonSchema(object) or of type UnEmployedPersonSchema(object). Can I use the OR operator like below?
const EmployedPersonSchema = new Schema({
employeeID: String,
taxNumber: Number
});
const UnEmployedPersonSchema = new Schema({
personID: String;
age: Number,
pensionNumber: Number
});
const PersonSchema = new Schema({
persons:{
type: [EmployedPersonSchema || UnEmployedPersonSchema],
default: []
}
});
Is it the best way to do it or there are other better ways? Any help?
DATA should look like below in my MongoDB:
"persons" : [
{
employeeID: "001",
taxNumber: 39765
},
{
personID: "901"
age: 68,
pensionNumber: 2345
}
]

Mongoose find returns empty array

I have mongoDB document which looks like this:
{
"_id": {
"$oid": "5b99247efb6fc01dae438815"
},
"participants": [
"5b758a8341ee61f049ded486",
"5b94fb4ffb6fc01dae40eae3"
]
}
The document Schema in Mongoose is defined as such
var conversationSchema = new mongoose.Schema({
participants: [{ type: mongoose.Schema.ObjectId, ref: 'User'}],
});
I am fetching the data as such
var ccc = Conversation.find({participants : "5b758a8341ee61f049ded486"});
ccc.exec(function(err, conversations){
res.status(200).json(conversations);
});
The problem is that I am getting an empty array response [].
I think the problem is with Schema but I can't figure out how can I make this to work.
EDIT,
If I change my Schema to the following it will work:
var conversationSchema = new mongoose.Schema({
participants: [{ type: String}],
});
But I want to work with mongoose.Schema.ObjectId and not Strings as foreign key.
Try adding Types to this line:
participants: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User'}]
It wont recognize the items in the array because they are strings you should have instead an object like {"$oid": "585bb0086c57cd2265b1cbd3"} so reinsert the items in you db and try again.

Mongoose populate array

I can't get mongoose to populate an array of objects.
The schema is as follows:
var topOrganisationsForCategorySchema = new mongoose.Schema({
category: String,
topOrganisations: [{
organisation: {
type: mongoose.Schema.Types.ObjectId,
ref: 'organisation'
},
model: mongoose.Schema.Types.Mixed
}]
});
module.exports = mongoose.model('topOrganisationsForCategory', topOrganisationsForCategorySchema);
I would like all of the objects in this collection populated with an array of organisations.
Here is what i have tried
TopOrganisationsForCategory
.find()
.exec(function(err, organisation) {
var options = {
path: 'topOrganisations.organisation',
model: 'organisation'
};
if (err) return res.json(500);
Organisation.populate(organisation, options, function(err, org) {
res.json(org);
});
});
var organisationSchema = new mongoose.Schema({
name: String,
aliases: [String],
categories: [String],
id: {
type: String,
unique: true
},
idType: String
});
organisationSchema.index({
name: 'text'
});
module.exports = mongoose.model('organisation', organisationSchema);
You're close but a couple notes:
The following code assumes you also have a schema/model declaration for Oranisation.
I am not sure if the model property is meant as an option (which would be invalid) or actually is a property of topOrganisations.
So, I left model in as it shouldn't cause any issues but be aware that if you were using it as an option it is not doing what you might think it is.
// Assuming this schema exists
var organisationSchema = new mongoose.Schema({...});
var topOrganisationsForCategorySchema = new mongoose.Schema({
category: String,
topOrganisations: [{
organisation: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Organisation' // Model name convention is to begin with a capital letter
}
// Is `model` supposed to be for the ref above? If so, that is declared in the
// Organisation model
model: mongoose.Schema.Types.Mixed
}]
});
// Assuming these model definitions exist
var Organisation = mongoose.model('Organisation', organisationSchema);
var TopOrganisationsForCategory = mongoose.model('TopOrganisationsForCategory', TopOrganisationsForCategorySchema);
// Assuming there are documents in the organisations collection
TopOrganisationsForCategory
.find()
// Because the `ref` is specified in the schema, Mongoose knows which
// collection to use to perform the population
.populate('topOrganisations.organisation')
.exec(function(err, orgs) {
if (err) {
return res.json(500);
}
res.json(orgs);
});

MongoDB $pull value from array of ObjectIDs

I have this document in my collection:
{
"_id" : ObjectId("52718433e18a711923000005"),
"owners" : [
ObjectId("52718433e18a711923000004"),
ObjectId("52ed40dccc5bc50000000003"),
ObjectId("52ed4171abe2780000000003")
]
}
I have the following statement, where I am trying to remove one of the values in owners field:
Business.update({_id:req.body._id}, {$pull:{"owners":req.body.userid}}, function(err){
if(err){
res.json(500, {message:"Could not remove user from admin list"});
}else{
res.json(200);
}
});
I know that req.body._id and req.body.userid have valid values:
{ _id: '52718433e18a711923000005',
userid: '52ed4171abe2780000000003' }
Other operations, such as finding business by ID, etc, work, so it's not an ObjectId format issue. What else could it be?
--
Edit: here is my (abbreviated) schema definition:
var BusinessSchema = new Schema({
business_name: {type: String, required: true},
owners: {type: Array}
});
Your current schema doesn't provide any direction to Mongoose regarding the data type contained within the owners array field. If you want Mongoose to cast your string to an ObjectID you need to provide type information in your schema:
var BusinessSchema = new Schema({
business_name: {type: String, required: true},
owners: [{type: Schema.ObjectId}]
});
It looks like a conversion to ObjectId is required when trying to match values to pull. But not to search. So this works:
var ObjectId = require('mongoose').Types.ObjectId;
Business.update({_id:req.body._id}, {$pull:{"owners": new ObjectId(req.body.userid)}}, function(err){
if(err){
res.json(500, {message:"Could not remove user from admin list"});
}else{
res.json(200);
}
});
--
Edit: So, if I change my schema from owners: {type: Array} to owners: [Schema.Types.ObjectId], I can skip the conversion, and my original statement works.