Mongoose/MongoDb ,how to validate an array of Ids against another model - javascript

I have 2 moongose Schema:
var Schema2 = new Schema({
creator : { type: String, ref: 'User'},
schema_name : [{ type: String}],
});
var Schema1 = new Schema({
creator : { type: String, ref: 'User'},
schema_ref : [{ type: String, ref: 'Schema2' }],
});
Would like to know which is the best practice when I create a new Schema1 check that every element of array schema_ref, have the same creator.
Because schema1 elements are added by client form and so i have to check that the schema_ref elements are owned by same User that send the form

You can try with either validator function, or with a simple 'save' middleware:
Schema1.pre('save', function(next) {
let owner;
for (let entry in this.schema_ref) {
if (!owner) {
owner = entry;
} else {
if (entry !== owner) {
return next(new Error("owner mismatch");
}
}
}
});
Also, your schema might not work as you expect it to, it looks like you actually need:
schema_ref: [{
type: {type: String},
ref: "User"
}]
Additionally, take a look at id-validator plugin, or some similar to that - it will, in addition to your validation, also check that all ref-type properties like this actually exist in the other (Users) collection.

Related

Mongoose .stream doesn't have populated fields

I have a schema "Reports" that looks like this:
var Reports = new Schema(
{
identifiersub: { // Id of reported submission, populate stuff
type: Schema.Types.ObjectId,
ref: "Submission"
},
identifiercom: { // Id of reported comment, populate stuff
type: Schema.Types.ObjectId,
ref: "Comments"
},
identifieruse: { // Id of reported user, populate stuff
type: Schema.Types.ObjectId,
ref: "AccountDetails"
},
solved: { // Whether this problem has been solved or not
type: Boolean,
default: false
},
processed: [{ // Array of moderators who were participating in processing this report
type: Schema.Types.ObjectId,
ref: "AccountDetails"
}],
type: String, // Type of content. bug, user, submission or comment
reports: [ // Additional text for each type of reported content
{
description: String, // Text from select component. For bugs: the feature that is affected,
reason: String, // Reason for this report
by: { // Reporter
type: Schema.Types.ObjectId,
ref: "AccountDetails"
}
}
],
notes: [{ // Admin notes
title: String, // Fleshed out discussion/reasoning
note: String, // Decided outcome that each note represents
outcome: String, // ("Keep reported", "delete", etc)
date: Date, // Date this note was added
moderator: { // Moderator who added this note
type: Schema.Types.ObjectId,
ref: "AccountDetails"
}
}]
},
{ strict: false, timestamps: true }
)
And in my admin panel I want to implement a search function that searches all reports with the specified keyword. The most important field here is reports: it's an array of objects containing a "by" field which is an ObjectId. Now I wanted to populate the username for this id, but I'm not seeing it in my document...I use the .stream method to check the whole document including nested objects and arrays of objects. Here's my query:
var cursor = Reports
.find({ type: req.query.type})
.limit(500)
.populate("notes.moderator reports.by processed", "username")
.populate("identifieruse", "username dob email ipaddress")
.populate("identifiercom", "by.username comment")
.populate("identifiersub", "meta.title by deleted")
.sort("-createdAt")
.lean()
.stream();
cursor.on('data', function(doc) {
console.log(doc);
if (doc.toString().includes(key)) results.push(doc)
})
cursor.on('error', function(err) {
return catcherror(new Error(err), res)
})
cursor.on('close', function() {
console.log(results);
return res.send(results)
})
Thanks for help!
Use .cursor() instead of .stream() and it works.

How to push element parent in Mongoose?

I want to push an nested element Mongoose.
Check the schema:
const Messages = new mongoose.Schema({
/*[user]*/
author: {
type: Schema.Types.ObjectId,
ref: 'Users'
},
/*[room]*/
room: {
type: Schema.Types.ObjectId,
ref: 'Rooms'
},
message_body: String,
message_status:{type: Boolean, default: false},
created_at: { type: Date, default: Date.now }
});
I want to create a Message with room and Author insert, how to use that?
Imagine you have an 'author' object and a 'room' object. These are going to be the parents. Your message object would be like this:
var newMessage = new Message({author: authore._id, room: room._id, message_body: messageBody ....});
newMessage.save()
.then(() => {
/*** do more things **/
});
Then you will be able to use 'populate' option to make Mongoose refilling author and room fields with the whole objects.

Does order of schema matter in Node.JS?

Im about to make a huge schema for a form that I have just built... that being said does my schema order have to mimic the form order, or can it just have all the inputs in any order I put them in ?
Example below.
can it be like this?
// link to mongoose
var mongoose = require('mongoose');
// define the article schema
var mapSchema = new mongoose.Schema({
created: {
type: Date,
default: Date.now
},
dd1: {
type: String,
default: ''
},
dd2: {
type: String,
default: ''
},
com1: {
type: String,
default: ''
},
com2: {
type: String,
default: ''
}
});
// make it public
module.exports = mongoose.model('Map', mapSchema);
Or does it have to be like this?
// link to mongoose
var mongoose = require('mongoose');
// define the article schema
var mapSchema = new mongoose.Schema({
created: {
type: Date,
default: Date.now
},
dd1: {
type: String,
default: ''
},
com1: {
type: String,
default: ''
},
dd2: {
type: String,
default: ''
},
com2: {
type: String,
default: ''
}
});
// make it public
module.exports = mongoose.model('Map', mapSchema);
does my schema order have to mimic the form order, or can it just have all the inputs in any order I put them in?
mongoose.Schema accepts a JavaScript object as its parameter. So your question boils down to:
Are JavaScript objects aware of the order their keys were defined in?
The answer to that is: No, key order is not maintained in JavaScript objects. The JS spec explicitly states that objects are unordered key/value collections. (compare)
Therefore it follows that mongoose.Schema could not rely on key order even if it tied to, which means you are free to order the keys in any way you like.
We can also tackle the question from the other end:
Is it likely that a front-end change like form field order forces me to rewrite my database backend code?
And the answer to that is: No, that is pretty darn unlikely. We can dismiss that thought without even looking into any kind of spec, because it would not make any kind of sense.

Mongoose typeError with custom Schema

I'm trying to use discountSchema as a type. But I'm getting this error:
throw new TypeError('Undefined type at `' + path +
^
TypeError: Undefined type at `discount`
but if I transform to type array:
discount: {
type: [discountSchema],
default:{}
}
it works.
How can I use complex type in mongoose as this?
Am I using this model in a wrong way? How can I model this object like this?
var discountSchema = new Schema({
type: {type: String,default:'' },
quantity: {type: Number,default:0 },
value: {type: Number,default:0 }
});
var objectEncomendaPropertiesSchema = {
recheios:{
type:[String],
default: [],
select: true
},
availableEncomenda: {
type: Boolean,
default:false
},
discount: {
type: discountSchema,
default:{}
}
};
You cant't set embedded documents stored as single property in mongoose, they are always stored in arrays.
The closest thing to this behaviour is setting your property to an ObjectId with a ref and using the populate method to fetch it.
Take a look here to see how this approach works.
Check out embedded documents docs.
There is an open issue on GitHub requesting the behaviour you want.
are you trying to create two Schemas then wire them up?
var discountSchema = new Schema({
type: {type: String,default:'' },
quantity: {type: Number,default:0 },
value: {type: Number,default:0 }
});
mongoose.model('Discount', discountSchema);
var objectEncomendaPropertiesSchema = new Schema({
recheios:{
type: String,
default: '',
select: true
},
availableEncomenda: {
type: Boolean,
default:false
},
discount: {
type: Schema.Types.ObjectId,
ref: 'Discount'
}
})
mongoose.model('objectEncomendaProperties', objectEncomendaPropertiesSchema);
I reference the discount in the second schema to reference to the first schema by the ObjectId
It will fetch the properties in the Discount model as a discount property in the second Schema.

Inserting Object ID's into array in existing Mongoose schema with Node.js

I have an existing News articles section that I want to add categories to for more refined searching, my Schema's are as follows:
var ArticleSchema = new Schema({
title: String,
body: String,
author: {
type: Schema.Type.ObjectId,
ref: 'User',
required: true
},
image: String,
catagories: [{
type: Schema.Types.ObjectId, ref: 'Catagory'
}],
meta: {
created: {
type: Date,
'default': Date.now,
set: function(val) {
return undefined;
}
},
updated: {
type: Date,
'default': Date.now
}
}
});
ArticleSchema.statics.search = function (str, callback) {
var regexp = new RegExp(str, 'i');
return this.find({'$or': [{title: regexp}, {body: regexp}]}, callback);
};
module.exports = ArticleSchema;
var CatagorySchema = new mongoose.Schema({
name: { type: String, unique: true },
});
module.exports = CatagorySchema;
I want a user friendly input for selecting categories (don't even know what is best here, be it check-box's or a simple comma separated text input etc.). My question is what is the best practice for obtaining this kind of input and translating that into the Article Schema (providing the categories exist). If anyone could point me in the right direction it would be much appreciated. Thanks.
Keep the category names you want to search for in an array
{
categories: ["cat1", "cat2"]
}
then you can add an index to it and do a $in query. the current schema is not very good because you cannot look for the category in a single query but need to resolve all the "categories" links first.

Categories

Resources