Complex Schema with subdocument - javascript

UPDATE:
Currently i have this schema:
var Schema = new schema ({
name: String,
type: { type: String },
date: { type: Date },
descrip: String,
});
But i use this schema for generate 2 documents:
THE A TYPE ({
name: 'A',
type: 'TYPE_B',
date: { type: Date },
descrip: 'DESC_A',
});
THE B TYPE ({
name: 'B',
type: 'TYPE_B',
date: { type: Date },
descrip: 'DESC_B',
});
The name, type and descrip are always the same in the A and B types, the only thing that changes is the date field, so i was thinking, how can i improve this? How can i insert several dates in the same schema, instead of create always an document with the same name, type and descrip values?
So i am trying to create a schema inside other schema, but i dont know if this is possible, it is?
I was trying like this:
var mainSchema = new schema ({
name: String,
type: { type: String },
date: [ dateSchema ],
descrip: String,
});
var dateSchema = new Schema ({
date: {
type: Date
}
});
What i want, is create two mainSchema, type a and type b, and insert dates inside...
Am i doing this right? How can i achieve my goals?
I am searching for a full answer with good explanation, that's why the bounty. I don't accept +/- answers.

To create a record with multiple dates you can use array of Dates.
var mainSchema = new schema ({
name: String,
type: { type: String },
dates: [Date],
descrip: String,
});
The documents will be as follows
THE A TYPE ({
name: 'A',
type: 'TYPE_B',
dates: ["2014-01-22T14:56:59.301Z","2015-01-22T14:56:59.301Z"],
descrip: 'DESC_A',
});
THE B TYPE ({
name: 'B',
type: 'TYPE_B',
dates: ["2015-01-22T14:56:59.301Z","2014-01-22T14:56:59.301Z"],
descrip: 'DESC_B',
});
Reference: http://mongoosejs.com/docs/schematypes.html
For saving the document you can use like.
exports.save = function(req,res){
var test = new newSchema; // new object for newSchema domain.
test.name= req.body.name;
test.type= req.body.type;
test.desc= req.body.desc;
if(req.body.date){
req.body.forEach(function(date){ // For every element of date from client.
test.date.push(date) // This pushes each and every date given from the client into the date array.
})
}
test.save(function (saveErr, saved) { // Saves the new document into db.
if (saveErr) {
console.log(saveErr)
return;
}
res.status(HttpStatus.OK).json(saved);
});
};
For Update you can use like.
exports.update = function(req,res){
newSchema.findOne({name: 'B'},function(err,test){ // Finds a record with name:'B' and stores in test the same can be done for name:'A'.
if(test){
if(req.body.date){
req.body.forEach(function(date){
test.date.push(date) // pushes dates into existing test document (update).
})
}
test.save(function (saveErr, saved) { // Saves (updates) the document.
if (saveErr) {
console.log(saveErr)
return;
}
res.status(HttpStatus.OK).json(saved);
});
}
});
};
Hope this helps.

If your code write down in one section it will look like this
var mainSchema = new schema ({
name: String,
type: { type: String },
date: [ {date: { type: Date } } ],
descrip: String,
});
I think that's wrong. Also you don't need to creat new schema like this, you can use just {} in your code http://www.w3schools.com/js/js_objects.asp . I think correct code must look like this:
var mainSchema = {
name: string,
date: {},
descrip: string
}
And then push into 'date' your dates. Good luck.
======================== HOW TO USE =======================
Sorry for delay. You can use mainSchema.date.date_1 = date; or you can chang date: {}, to date: [], and use mainSchema.date.push(date) depend on your needs.

Related

document not filtered by property

My document item looks like that:
I'm trying to filter the document by year like that:
async function getBooksByYear(year: number): Promise<Book[]> {
return BookModel.find({'year': year})
}
I send the request from postman: http://localhost:4000/api/books?year=1990
but it's not working - it's returning the entire document items
appreciate any help
The answer is: this property wasn't declared in the schema.
when I add the year to the schema:
export const BookSchema = new mongoose.Schema<Book>({
author: {
type: String,
required: [true, "missing author name"]
},
country: {
type: String,
required: [true, "missing country"]
},
// I add this part now
year: {
type: Number
}
})
it works :)

Mongoose update nested object in array of record

I am currently having a problem where I am trying to update an of a nested array in a Mongoose record.My schema is as follows:
const customerSchema = new mongoose.Schema({
kimCustomerId: {
type: Number,
required: true
},
addresses: [
{
created: Date,
updated: Date,
addressInfo: {
type: { type: String },
typeOfAddress: String,
careOf: String,
address: String,
addressRow1: String,
addressRow2: String,
zipcode: String,
city: String,
countryCode: String,
physicalAddressType: String,
validFrom: Date,
validTo: Date
}
}
],
.....
As you can see, the adrress array for each record holds many addresses. I want to be able to pass through an update object and update the properties inside the addressInfo nested object inside a particular array object. Here is my query as it stands:
const updated = await db.models.customers.findOneAndUpdate(
{
_id: customer._id,
'addresses.addressId': addressData.addressId
},
{ $set: { 'addresses.$': addressData } },
{ new: true }
);
and an example of an object I pass through to update a record:
{
addressId: officialAddressExists.addressId,
addressInfo: {
validTo: new Date().toISOString()
}
}
What I want to happen is, when I pass this object to the schema method, I want to select the correct address by the values 'kimCustomerId' and 'addressId' (which I have working fine) then only update the values of the 'addressInfo' nested object that I have passed and keep the ones not passed as they are, in this case the 'validTo' field but it can be any number of them updated. It is overwriting the whole 'addressInfo' nestedObject at the moment so I presume I have to do some kind of set operation on that nested object as well but I am unsure how.
Is anyone able to point me in the right direction here?
Thanks!
There is no straight way to do this in query, you can do it in your client side, something like,
// Sample body request
let addressData = {
addressId: 1,
addressInfo: {
validTo: new Date().toISOString(),
typeOfAddress: "Home",
address: "ABC"
}
};
let set = {};
for (let key in addressData.addressInfo) {
set["addresses.$.addressInfo." + key] = addressData.addressInfo[key];
}
console.log(set);
Pass set variable in to your query,
const updated = await db.models.customers.findOneAndUpdate(
{
_id: customer._id,
'addresses.addressId': addressData.addressId
},
{ $set: set },
{ new: true }
);

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

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.

Updating a child object property of a parent object which needs to be populated in mongoose

I'm new to Mongoose and I'm having difficulty getting my head around accessing properties deeper in the model and updating properties on the following model structures.
Game Schema
var gameSchema = new Schema({
opponents: [{
type: Schema.Types.ObjectId,
ref: 'teams'
}],
startTime: { type: Date, default: Date.now },
endTime: Date,
pauses: [{
start: Date,
end: Date
}],
winner: {
type: Schema.Types.ObjectId,
ref: 'teams'
},
status: {type: String, default: "created"},
score: [{
"opponent1": {type: Number, default: 0},
"opponent2": {type: Number, default: 0}
}],
}, { versionKey: false });
Team Schema
var teamSchema = new Schema({
name:String,
badge:String,
goals:[{type: Date, default: Date.now}],
totalWins:Number
}, { versionKey: false });
My problem is I'm trying to add a goal to a team from a specific game.
So my end point:
POST: /api/game/GAME_ID/goal
DATA: {_id: TEAMID}
I thought the following would work:
Games.findById(GAME_ID)
.populate('opponents')
.find({'opponent._id': TEAM_ID})
.exec(function(err, team) {
// Team from game with matching ID returned
// Now push goal time into array
team.goal.push(Date.now());
});
The above does not appear to return a team. if I remove the second find the game is returned and then I have to do something horrible like this:
Games.findById(GAME_ID)
.populate('opponents')
.exec(function(err, game) {
if(game.opponents[0]._id.toString() === req.body._id) {
game.opponents[0].goals.push(Date.now());
} else if (game.opponents[1]._id.toString() === req.body._id) {
game.opponents[1].goals.push(Date.now());
} else {
// Throw error no matching team with id
}
});
game.save(function(err, game) {
//Game saved
});
this last example appears to work but when I try to add further goals pushing into the goals array it overwrites the old goal time.
So to recap.
How do I query the Games model to retrieve a child by id which has
yet to be populated?
How do I set push the goal time stamp into the goals array without
overwriting the previous one?
Is it possible to do these a bit more gracefully than the current example given above.
Games.findById(GAME_ID)
.populate(
path: 'opponents',
match: { _id: TEAM_ID}
)
.exec(function(err, team) {
// Team from game with matching ID returned
});

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