MongoDB Object data type won't save with defined schema - mongodb

Using Mongo and Meteor with CoffeeScript, I'm trying to save a document with one Object:
Test = new SimpleSchema(
tag:
type: Object
)
And the insert:
test1 = new Meteor.Collection("test", { schema: Test})
test1.insert({ tag: {"name": "campus"} })
Result: a document gets saved in the database but the "tag" field is never set.
Couple of different troubleshooting steps I've taken:
Changing the data type to String works and the "tag" field gets set. However, I want to reference a tag property without having to parse the string every time.
Adding a collection without the schema saves the Object exactly how I want:
test2 = new Meteor.Collection("test2")
test2.insert({ tag: {"name": "campus"} })
EDIT: Fixed using the blackbox: true flag. See below answer for clarification.
Test = new SimpleSchema(
tag:
type: Object
blackbox: true
)

According to SimpleSchema docs, all defined properties must pass validation. So any Object data type without properties is treated as an empty Object unless you add the blackbox: true flag.
Source: http://atmospherejs.com/aldeed/simple-schema#blackbox
If you have a key with type Object, the properties of the object will be validated as well, so you must define all allowed properties in the schema. If this is not possible or you don't care to validate the object's properties, use the blackbox: true option to skip validation for everything within the object.

I use simple schema and create my models of the following way, and I don't have any problem.
Test = new Meteor.Collection("test", {
schema: new SimpleSchema({
ownerId: {
type: String,
},
dateAdd: {
type: Date,
}
})
})
Test.insert({ownerId:"123",dateAdd:"..."})
In Coffee Script
Test = new Meteor.Collection("test",
schema: new SimpleSchema(
ownerId:
type: String
dateAdd:
type: Date
)
)

Related

How to use Object type in mongose schema?

I am trying to store the amount of time an employee has worked in my MongoDB database, but not able to make a mongoose schema whose type will object.
The desired database should have a document like this:
{
name: 'name of employee',
report: {'01-01-2023':5hr, '02-01-202':7hr, '03-01-2023':8hrs}
}
This report will contain an object whose key will be a date and the value will be minutes or hours an employee has worked on that date.
how can I make a schema to achieve the desired goal, I have tried like this but did not work.
const UserSchema = new mongoose.Schema({
name:{
type: String,
required: true
},
report: {
type: Object, // what should I write here
}
})

Mongoose set default on field update if field is not present or null

I have a mongoose schema like this suppose:-
var mSchema = new Schema({
name: { type: String, required: true}
});
and have been using this schema for a year and now i want to add gender to it like this :-
var mSchema = new Schema({
name: { type: String, required: true},
gender: { type: String, default: 'Male' }
});
whenever there will be an update request i want this gender to automatically set Male as default but i found that default don't set on update request.
(Note: It's just an example not a real life scenario. i just want mongoose default work if field is not present or null)
Is there any way in which i can set default on the updation of document ?
If you are using a function like update(), then this is not directly possible as stated by this answer. Still, you can simply switch to a function like findOne() and use save(), which should do the same.
When upserting documents, you can also check out the setDefaultsOnInsert option: https://mongoosejs.com/docs/defaults.html#the-setdefaultsoninsert-option
const options = {
// Create a document if one isn't found. Required
// for `setDefaultsOnInsert`
upsert: true,
setDefaultsOnInsert: true
};
await XY.findOneAndUpdate(query, update, options);

populating inner attribute within sub object in mongoose document

I have a following type of schema and I want populate the guide details when getting a tour document. I tried with Tour.findById(id).populate({path: 'summary.guide'}). But in the result it returns a null for guide. How to populate that guide details?
const tourSchema = new mongoose.Schema({
from: String,
to: String,
summary: {
guide: { type: Schema.Types.ObjectId, ref: 'User' },
duration: Number,
distance: Number
}
})
I think you should not pass the user id into the summary.guide object.
The second possibility is user id and summary.guide not match.
The third possibility is summary.guide is not exist.
this code works for me
Tour.findById("5dcd2c61...").populate({path: 'summary.guide'});

Updating an array field in a mongodb collection

I am trying to update my collection which has an array field(initially blank) and for this I am trying this code
Industry.update({_id:industryId},
{$push:{categories: id:categoryId,
label:newCategory,
value:newCategory }}}});
No error is shown, but in my collection just empty documents({}) are created.
Note: I have both categoryId and newCategory, so no issues with that.
Thanks in advance.
This is the schema:
Industry = new Meteor.Collection("industry");
Industry.attachSchema(new SimpleSchema({
label:{
type:String
},
value:{
type:String
},
categories:{
type: [Object]
}
}));
I am not sure but maybe the error is occuring because you are not validating 'categories' in your schema. Try adding a 'blackbox:true' to your 'categories' so that it accepts any types of objects.
Industry.attachSchema(new SimpleSchema({
label: {
type: String
},
value: {
type: String
},
categories: {
type: [Object],
blackbox:true // allows all objects
}
}));
Once you've done that try adding values to it like this
var newObject = {
id: categoryId,
label: newCategory,
value: newCategory
}
Industry.update({
_id: industryId
}, {
$push: {
categories: newObject //newObject can be anything
}
});
This would allow you to add any kind of object into the categories field.
But you mentioned in a comment that categories is also another collection.
If you already have a SimpleSchema for categories then you could validate the categories field to only accept objects that match with the SimpleSchema for categories like this
Industry.attachSchema(new SimpleSchema({
label: {
type: String
},
value: {
type: String
},
categories: {
type: [categoriesSchema] // replace categoriesSchema by name of SimpleSchema for categories
}
}));
In this case only objects that match categoriesSchema will be allowed into categories field. Any other type would be filtered out. Also you wouldnt get any error on console for trying to insert other types.(which is what i think is happening when you try to insert now as no validation is specified)
EDIT : EXPLANATION OF ANSWER
In a SimpleSchema when you define an array of objects you have to validate it,ie, you have to tell it what objects it can accept and what it can't.
For example when you define it like
...
categories: {
type: [categoriesSchema] // Correct
}
it means that objects that are similar in structure to those in another SimpleSchema named categoriesSchema only can be inserted into it. According to your example any object you try to insert should be of this format
{
id: categoryId,
label: newCategory,
value: newCategory
}
Any object that isn't of this format will be rejected while insert. Thats why all objects you tried to insert where rejected when you tried initially with your schema structured like this
...
categories: {
type: [Object] // Not correct as there is no SimpleSchema named 'Object' to match with
}
Blackbox:true
Now, lets say you don't what your object to be filtered and want all objects to be inserted without validation.
Thats where setting "blackbox:true" comes in. If you define a field like this
...
categories: {
type: [Object], // Correct
blackbox:true
}
it means that categories can be any object and need not be validated with respect to some other SimpleSchema. So whatever you try to insert gets accepted.
If you run this query in mongo shell, it will produce a log like matched:1, updated:0. Please check what you will get . if matched is 0, it means that your input query is not having any matching documents.

Does using dbref do anything more than just storing an `id`

My Mongoose schema:
// set up the schema
var CategorySubSchema = new Schema({
name: { type: String },
_category_main : { type: String, ref: 'CategoryMain' }
},
And my controller code:
CategorySub.create({
name : req.body.name,
_category_main : req.body.category_main
}, function(err, data){
An entry in my db:
{
"_id": "54dd163434d78ae58f6b1a69",
"name": "Snacks",
"_category_main": "54dcf4a71dfecb4d86ddcb87",
"__v": 0
},
So I used an underscore, because I was following an example. Does this mean anything to the database or is it just convention for references?
Also, instead of passing the entire JSON object in the request - req.body.category_main, why not just pass and id and change my schema to this?:
var CategorySubSchema = new Schema({
name: { type: String },
category_main_id : { type: String }
},
In short, Yes.
The below schema definition is an example of Manual references.
var CategorySubSchema = new Schema({
name: { type: String },
category_main_id : { type: String }
}
where,
you save the _id field of one document in another document as a
reference. Then your application can run a second query to return the
related data. These references are simple and sufficient for most use
cases.
In this case, we need to write explicit application code to fetch the referred document and resolve the reference. Since the driver that we use wouldn't know about the collection in which the referred document is present nor the database in which the referred document is present.
When you define the schema as below, this is an example of storing the details of the referred document .(Database references)
var CategorySubSchema = new Schema({
name: { type: String },
_category_main : { type: String, ref: 'CategoryMain' }
}
They include the name of the collection, and in some cases the
database name, in addition to the value from the _id field.
These details allow various drivers to resolve the references by themselves, since the name of the collection and the database(optional) of the referred document would be contained in the document itself, rather than we writing explicit application code to resolve the references.
So I used an underscore, because I was following an example. Does this mean anything to the database or is it just convention for
references?
Using underscore in the _id field is a valid naming convention, but mongoDb doesn't explicitly mention about the naming convention of other fields which are used to resolve references. You could just use any other field name as long as it conforms to this.