I am building an API that gives info about laptops. I am using node and mongoDB with mongoose for this. This is my Schema -
const productSchema = mongoose.Schema(
{
name: {
type: String,
required: [true, 'A product must have a name'],
unique: true,
},
},
{
toJSON: {
virtuals: true,
},
toObject: {
virtuals: true,
},
});
I have a name field. I also want a "specs" field that should be an object. I want define rules for the properties in the object of the "specs" field. What I expect to come in the specs field is -
specs: {
memory: "16gb",
storage: "512gb",
"processor": "i7 2.2ghz"
}
So, I want to define rules for 'memory', 'storage', 'processor' in the 'specs' object
If by rules you mean a schema object rules, then possibly something like this would do:
specs: {
memory: {
type: String,
default: null
},
storage: {
type: String,
default: null
},
processor: {
type: String,
default: null
}
}
You can add more rules as you need.
Related
I needed a property of date/time which would allow to me get the time at which a certain task was created, I added timestamp property and set it to be true,
But I m not able to compile my code.
The code is perfectly running fine without the timestamp property
const mongoose = require("mongoose");
const Task = mongoose.model(
"Task",
({
title: {
type: String,
required: true,
trim: true,
},
description: {
type: String,
required: true,
trim: true,
minLength: 100,
},
completed: {
type: Boolean,
default: false,
},
},
{ timestamps: true })
);
module.exports = Task;
I needed a property of date/time which would allow to me get the time at which a certain task was created, I added timestamp property and set it to be true,
But I m not able to compile my code.
The mongoose.model() function of the mongoose module is used to create a collection of a particular database of MongoDB. The name of the collection created by the model function is always in plural format mean GFG to gfss and the created collection imposed a definite structure.
Syntax:
mongoose.model(<Collectionname>, <CollectionSchema>)
Parameters: This function accepts the following two parameters:
Collection name: It is the name of the collection.
Collection Schema: It is the schema of the collection.
Return type: This function returns the Mongoose object.
You need to pass a valid schema for the second argument like below
const mongoose = require("mongoose");
const TodoModel = mongoose.model(
"Task",
new mongoose.Schema(
{
title: {
type: String,
required: true,
trim: true,
},
description: {
type: String,
required: true,
trim: true,
minLength: 100,
},
completed: {
type: Boolean,
default: false,
},
},
{ timestamps: true }
)
);
module.exports = TodoModel;
More about what is a valid schema refer below
https://mongoosejs.com/docs/schematypes.html
I have an update call as below in my NestJs project to update a mongoose model.
async updateRole(role_id: ObjectId, request: any): Promise<any> {
return this.roleModel.findByIdAndUpdate(role_id, {...request});
}
Here is the request I'm passing
{
"name":"Super-Admin",
"application": "62b2dbfd82045f40ea884334",
"active":true,
"privileges": ["62b2dbfd82045f40ea884334","62b2dbfd82045f40ea884334"],
"updated_by": "Abhilash.Shajan1#gmail.com"
}
Below is my role schema
import * as mongoose from 'mongoose';
const Schema = mongoose.Schema;
const RoleSchema = new Schema({
name: {
type: String,
required: true
},
application: {
type: Schema.Types.ObjectId,
ref: 'Application',
autopopulate: true,
required: true
},
active: {
type: Boolean,
required: true
},
privileges: [{
type: Schema.Types.ObjectId,
ref: 'Privilege',
autopopulate: true
}],
created_by: {
type: String
},
created_at: {
type: Date
},
updated_by: {
type: String
},
updated_at: {
type: Date
}
});
RoleSchema.index( { name: 1, application: 1 }, { unique: true } );
export { RoleSchema };
I already created a document (This is the only document now present in the roles collection) with the above request. Now I'm trying to update its active field to true.
Since i have unique compound index in the schema, it does not allow me to update the active field, I'm getting unique contraint error on both application and name field.
This error will be meaningful if i have another document with same name and application in the collection, but there is not.
Another way is to pass the active field alone in the request. But it will not help in my case because the UI is always passing the whole fields which include the unchanged values as well.
Any suggestions ?
I need to get a nested object within a certain document (searched by user ID) that also has an object inside of it (there's no guarantee that this object will be the same object).
I have the User model to be:
const mongoose = require('mongoose');
const { bool } = require('#hapi/joi');
const monitoringSchema = new mongoose.Schema({
type: Object,
default: {}
})
const hubSchema = new mongoose.Schema({
hubID: {
type: String,
default: ""
},
isSetup: {
type: Boolean,
default: false
},
monitoring: {
type: monitoringSchema
}
}, {strict:false})
const finalUserSchema = new mongoose.Schema({
username: {
type: String,
required: true,
max: 255
},
email: {
type: String,
required: true,
max: 255,
},
password: {
type: String,
required: true,
min: 10,
max: 1024,
},
date: {
type: Date,
default: Date.now
},
isVerified: {
type: Boolean,
default: false
},
hub: {
type: hubSchema
}
}, {strict:false});
module.exports = mongoose.model('User', finalUserSchema);
OR It has the layout:
_id: "id"
isVerified: true
username: "nathan"
email: "email#email.com"
hub:
hubID: "id"
monitoring: // WHOLE OBJECT I NEED TO RETREIVE
exampleObject:
exampleValue: exampleKey
I have an array of user IDs I need to update and I tried the query:
for(i in usersToUpdate){
User.findOne({_id: usersToUpdate[i], "hub.monitoring": {}}, {}, callbackResponse);
function callbackResponse(err, data){
if(err) return console.log(err)
console.log(data)
}
}
But it returns null as the data so obviously the query is wrong. I know the error is:
{_id: usersToUpdate[i], "hub.monitoring": {}}
more specifically:
"hub.monitoring": {}
I'm using {} to reference an object within monitoring, what's the correct reference to reference an unknown object and get it's values back, like a wildcard? I've tried:
{_id: usersToUpdate[i], "hub.monitoring": Object}
and it still doesn't work. I've seen this answer, however they reference a value that they already know, like a name?
To retrieve only the monitoring object, aggregation pipeline can be used.
Using $match to filter and $project to output/ supress fields.
User.aggregate([
{
$match: {
_id: mongoose.Types.ObjectId(usersToUpdate[i]),
},
},
{
$project: {
monitoring: "$hub.monitoring",
_id: 0,
},
},
]).exec(callbackResponse);
Playground example
You can try using the 2 object form of findOne where the first object is the query and the second object is the projection of what you want to return.
User.findOne({_id: usersToUpdate[i]}, {"hub.monitoring": {$exists: true}}, callbackResponse);
function callbackResponse(err, data){
if(err) return console.log(err)
console.log(data)
}
This way, the object will be returned if the monitoring object exist.
I have the following schema and subschema:
The child schema:
const SettingSchema = new Schema({
settingIdentifier: {
type: String,
required: true
},
shareLink: {
type: String,
required: true
},
downloadLink: {
type: String,
required: true
},
direction: {
type: String,
required: true
}
});
And the parent schema:
const DeviceSchema = new Schema({
id: {
type: String,
required: true
},
store: {
type: String,
required: true
},
storeName: {
type: String,
required: true
},
deviceInfo: {
type: String,
required: true
},
contentSettings:{
type:[SettingSchema],
required: true
}
})
In my code, I want to get the child schema name from the retrieved document.
For example, I can get the document as such:
Device.findOne({ deviceInfo: "someValue" }).then(device => {
// device is the retrieved document
// with this device object, how do I get the device[settings] schema name?
// device[settings] is an array of SettingSchema with possibly multiple members
// Expected output : "SettingSchema"
});
So, how do I get the schema name of the subdocument "settings" when I have the "device" object?
Many thanks in advance.
Edit:
I'm attaching the console.log to show what device contains after Device.findOne.
{
"_id": "5ea034d07d865e38c0d4ed6f",
"id": "1a89d59800a72e39",
"store": 1,
"storeName": "Singapore Store",
"deviceInfo": "test device2",
"contentSettings": [
{
"settingIdentifier": "NewYearEvent",
"shareLink": "share1",
"downloadLink": "dl1",
"direction": "D"
},
{
"settingIdentifier": "EasterEvent",
"shareLink": "share2",
"downloadLink": "dl2",
"direction": "H"
}
],
"__v": 0
}
So Device.findOne gets a device instance from the database and it contains the data, but I don't see the metadata to identify the type or schema name of device itself, or its members
I am trying to expand the Meteor.users collection and I've got everything working fairly well so far except for some reason with this it's not allowing me to register new users anymore. I am using the accounts-google package for login/registration, logging in with an account that's already been created works great but when I attempt to register with a new account it doesn't work and I receive the following error in my browser console:
Exception in delivering result of invoking 'login': ReferenceError: ServiceConfiguration is not defined
at http://localhost:3000/packages/useraccounts_core.js?e3a764dbf634d8bf2a393797c0a82e9fadef2e7a:2551:48
at Accounts.callLoginMethod.userCallback (http://localhost:3000/packages/accounts-oauth.js?8a30b216f87b515ab9b4bf5d4970a7113d0c6c2f:163:7)
at http://localhost:3000/packages/accounts-base.js?7dabd814506e384c709f8bf707377955f9814129:612:26
at http://localhost:3000/packages/underscore.js?46eaedbdeb6e71c82af1b16f51c7da4127d6f285:794:19
at loggedInAndDataReadyCallback (http://localhost:3000/packages/accounts-base.js?7dabd814506e384c709f8bf707377955f9814129:708:7)
at null._callback (http://localhost:3000/packages/meteor.js?9730f4ff059088b3f7f14c0672d155218a1802d4:999:22)
at _.extend._maybeInvokeCallback (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:3500:12)
at _.extend.receiveResult (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:3520:10)
at _.extend._livedata_result (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:4625:9)
at onMessage (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:3365:12)
Can anyone see where I went wrong here? I've been playing around with it for quite a while and just cant seem to get it to work. Any help/insight is greatly appreciated.
Schema = {};
Schema.UserProfile = new SimpleSchema({
userProfile: {
type: Object
},
'userProfile.firstName': {
type: String,
optional: true,
label: "First Name"
},
'userProfile.lastName': {
type: String,
optional: true,
label: "Last Name"
},
'userProfile.birthday': {
type: Date,
optional: true,
label: "Date of Birth"
},
'userProfile.contactEmail': {
type: String,
optional: true,
label: "Contact Email"
},
'userProfile.gender': {
type: String,
allowedValues: ['Male', 'Female'],
optional: true,
label: "Gender"
},
'userProfile.country': {
type: String,
optional: true,
label: "Country"
},
'userProfile.address': {
type: String,
optional: true,
label: "Address"
},
'userProfile.city': {
type: String,
optional: true,
label: "City"
},
'userProfile.stateProvince': {
type: String,
optional: true,
label: "State/Province"
},
'userProfile.postalCode': {
type: String,
optional: true,
label: "Postal Code"
},
'userProfile.phoneNumber': {
type: String,
optional: true,
label: "Phone Number"
},
});
Schema.User = new SimpleSchema({
username: {
type: String,
// For accounts-password, either emails or username is required, but not both. It is OK to make this
// optional here because the accounts-password package does its own validation.
// Third-party login packages may not require either. Adjust this schema as necessary for your usage.
optional: true
},
emails: {
type: Array,
// For accounts-password, either emails or username is required, but not both. It is OK to make this
// optional here because the accounts-password package does its own validation.
// Third-party login packages may not require either. Adjust this schema as necessary for your usage.
optional: true
},
"emails.$": {
type: Object
},
"emails.$.address": {
type: String,
regEx: SimpleSchema.RegEx.Email
},
"emails.$.verified": {
type: Boolean
},
createdAt: {
type: Date
},
profile: {
type: Schema.UserProfile,
optional: true
},
// Make sure this services field is in your schema if you're using any of the accounts packages
services: {
type: Object,
optional: true,
blackbox: true
},
// Add `roles` to your schema if you use the meteor-roles package.
// Option 1: Object type
// If you specify that type as Object, you must also specify the
// `Roles.GLOBAL_GROUP` group whenever you add a user to a role.
// Example:
// Roles.addUsersToRoles(userId, ["admin"], Roles.GLOBAL_GROUP);
// You can't mix and match adding with and without a group since
// you will fail validation in some cases.
roles: {
type: Object,
optional: true,
blackbox: true
},
// In order to avoid an 'Exception in setInterval callback' from Meteor
heartbeat: {
type: Date,
optional: true
}
});
Meteor.users.attachSchema(Schema.User);
Meteor.users.allow({
insert: function(userId, doc) {
// only allow posting if you are logged in
console.log("doc: " + doc + " userId: " + userId);
return !! userId;
},
update: function(userId, doc, fieldNames) {
// only allow updating if you are logged in
console.log("doc: " + doc + " userId: " + userId);
// a user can only update his own user doc and only the 'userProfile' field
return !! userId && userId === doc._id && _.isEmpty(_.difference(fieldNames, ['userProfile']));
},
});
Your standard 'new' user object does not match your schema and will fail on creation.
So, to get around this you want to reformat the output of the object provided by the Account.onCreateUser function:
Accounts.onCreateUser(function (options, user) {
//format the 'user' object as you need it to be here
// to pass your schema validation
return user;
})