I want to create an array of stores. And in each store, there would be sections. So one store maybe have a deli and produce section. Another store may just cashiers and a meat section.
var UserSchema = new Schema({
store: {
type: Array,
},
section: { // how do I put this inside the store array?
type: Array,
}
});
we can do it by by specifying type mixed, it will accept any kind of data structre
var UserSchema = new Schema({
store: [{
type: Schema.Types.Mixed
}]
});
Related
I have the following Schema with a array of ObjectIds:
const userSchema = new Schema({
...
article: [{
type: mongoose.Schema.Types.ObjectId,
}],
...
},
I will count the array elements in the example above the result should be 10.
I have tried the following but this doesn't worked for me. The req.query.id is the _id from the user and will filter the specific user with the matching article array.
const userData = User.aggregate(
[
{
$match: {_id: id}
},
{
$project: {article: {$size: '$article'}}
},
]
)
console.log(res.json(userData));
The console.log(article.length) give me currently 0. How can I do this? Is the aggregate function the right choice or is a other way better to count elements of a array?
Not sure why to use aggregate when array of ids is already with user object.
Define articles field as reference:
const {Schema} = mongoose.Schema;
const {Types} = Schema;
const userSchema = new Schema({
...
article: {
type: [Types.ObjectId],
ref: 'Article',
index: true,
},
...
});
// add virtual if You want
userSchema.virtual('articleCount').get(function () {
return this.article.length;
});
and get them using populate:
const user = await User.findById(req.query.id).populate('articles');
console.log(user.article.length);
or simply have array of ids:
const user = await User.findById(req.query.id);
console.log(user.article.length);
make use of virtual field:
const user = await User.findById(req.query.id);
console.log(user.articleCount);
P.S. I use aggregate when I need to do complex post filter logic which in fact is aggregation. Think about it like You have resultset, but You want process resultset on db side to have more specific information which would be ineffective if You would do queries to db inside loop. Like if I need to get users which added specific article by specific day and partition them by hour.
I have schema type Map in my mongoose model. In this map, each element has reference to another model. I know that it's possible to populate attributes in array, but how about Map type? Be cause nesting like "map_type_attribute.some_attribute_to_populate" doesn't work. :)
This is my model:
const Mongoose = require('mongoose');
const parameter = Mongoose.Schema({
definition: {
type: Mongoose.Schema.Types.ObjectId,
ref: 'Definition',
},
value: {},
}, {_id: false});
const schema = Mongoose.Schema({
model: {
type: Mongoose.Schema.Types.ObjectId,
ref: 'Model'
},
name: String,
objectid: Number,
externalId: String,
properties: Mongoose.Schema.Types.Mixed,
parameters: {
type: Map,
of: parameter
}
});
module.exports = Mongoose.model('Element', schema);
This is how i'm trying to populate definition field:
const request = Element.find(query, projection);
request.populate('parameters.definition');
request.exec( (err, docs) => {
...
This functionality was added in Mongoose 5.10.3 (September 2020). You simply denote every element in the map with a $*.
In your example this would be:
const request = Element.find(query, projection);
request.populate('parameters.$*.definition');
request.exec( (err, docs) => {
I also trying to find answer on this question. It seems that deep-populate work, but only if you put keys from the Map to populate method/function. In your case, if you have data like:
{
model: ObjectId("111"),
name: "MyName",
objectid: 111,
externalId: "ExternalId",
properties: ...,
parameters:{
"parameter1":{
"definition":ObjectId("333"),
"value":"value of parameter 1"
},
"parameter2":{
"definition": ObjectId("444"),
"value": "value of parameter 2"
}
}
}
Then you may find and populate like this:
Element.find({}).populate("parameters.parameter1.definiton")
But it's not a good solution. It would be nice if we have something like regexp inside this populate path.
Currently I've managed only to grab all inner collection, and then manually work with Map to substitude collections.
It shouldn't be a huge overhead, since you have only 2 queries to DB. In you case it can be like:
const elements = Element.find({});
const parameters = Parameter.find({});
// go through the elements.parameters and replace it with appropriate value from parameters collection.
I recently had to convert a project that had a lot of work done with ASP.NET Core 1.0 to Node.js. I'm absolutely out of my comfort zone, knowing hardly anything about JavaScript and having had the good life of ASP serializing C# classes for me without me having to do the JSON myself. Node wants me to do the JSON myself which I am having a bad time with.
It's a fitness app. You have clients with some progress containing their lifts and stuff. In C#, that is in a Workouts object, as seen below:
public struct Progress
{
public Workout[] Workouts;
}
Workouts is a re-usable object containing things like timing, sets, repetitions, all the good stuff. I could just re-write the Workouts object in every single one of my schemas that need it, but there must be a better way? I read something about $schema and $ref but am unfamiliar with how to use them or if this is the right application of those keywords.
Lastly, how would I define an array of this custom Workout object?
This is my JSON object and the contents of client.js so far. The progress bit is the thing that I'd ideally like to achieve.
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ClientSchema = new Schema({
measurements: [{
height: Number,
weight: Number
}],
personal_information: [{
birthday: Date,
gender: String
}],
contact_information: [{
phone: String,
email: String
}],
progress: [{
workouts: WorkoutList
}]
});
If you just want a common data structure that can be used in various other models then you can create a sub-doc schema (that may or may never have its own model) that will be used by various other schemas.
NOTE: This provides a singleton schema object which means if you were to modify it one model it would be propagated to any other models that later use it. If that is a concern than you can convert workout-list-schema.js to be a factory function that would return a new schema object each time.
workout-list-schema.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var WorkoutListSchema = module.exports.WorkoutListSchema = new Schema({
// some schema
});
client-schema.js
var mongoose = require('mongoose');
var WorkoutListSchema = require('./workout-list-schema').WorkoutListSchema;
var Schema = mongoose.Schema;
var ClientSchema = new Schema({
measurements: [{
height: Number,
weight: Number
}],
personal_information: [{
birthday: Date,
gender: String
}],
contact_information: [{
phone: String,
email: String
}],
progress: [{
workouts: WorkoutListSchema
}]
});
I have these mongoose schemas:
var ItemSchema = new Schema({
"pieces": Number,
"item": { type: Schema.Types.ObjectId, ref: 'Items' }
});
var cartSchema= new Schema({
"items": [ItemSchema]
});
but when I want to push a new item in items, mongoose add an _id field(on the new item) but I don't understand why.
if you want to add item without _id field then you should add { _id: false } in ItemSchema.
var ItemSchema = new Schema({
"pieces": Number,
"item": { type: Schema.Types.ObjectId, ref: 'Items' }
}, { _id: false });
Mongoose assigns each of your schemas an _id field by default if one is not passed into the Schema constructor. The type assigned is an ObjectId to coincide with MongoDB's default behavior. If you don't want an _id added to your schema at all, you may disable it using this option.
You can only use this option on sub-documents. Mongoose can't save a document without knowing its id, so you will get an error if you try to save a document without an _id.
Link: http://mongoosejs.com/docs/guide.html#_id
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.