document not filtered by property - javascript

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 :)

Related

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 }
);

MongoDB / NodeJS can't push to array

I am trying to add tags to existing tags in a MongoDB collection with this Schema:
const workSchema = new mongoose.Schema({
title: {
type: String,
required: "Tile can't be blank"
},
description: {
type: String
},
imageURL: {
type: String,
unique: true
},
workURL:{
type: String,
unique: true
},
tags:{
type:Array
},
createdDate: {
type: Date,
default: Date.now
}
});
const Work = mongoose.model('Work', workSchema);
module.exports = Work;
I made an API that makes a PUT request to "/api/work/:workId/tags"
exports.updateTags = (req, res) =>{
try{
const newTags = req.body.tags.split(',');
newTags.forEach(tag => {
db.Work.update(
{"_id": req.params.workId},
{
$push:{
tags: tag
}
}
)
})
res.status(200).send({message : "tags updated"})
}
catch(error){
res.status(400).send(error)
}
}
request.body:
{
tags:"a,b,c"
}
The problem is that the array won't update with the new tag values
I searched for other ways to update in the docs and on the web but I didn't find any solutions.
You haven't defined _id in your workSchema so the type of _id would be ObjectId
But req.params.workId is probably a String, so querying an ObjectId with a String won't work.
So you should convert req.params.workId to ObjectId using mongoose.Types.ObjectId
{ "_id": mongoose.Types.ObjectId(req.params.workId) }
But you can improve your code a bit more by using .findByIdAndUpdate and $each operator
.findByIdAndUpdate will automatically convert your _id to ObjectId
You can use $each to $push multiple array elements at the same time without using .forEach
Work.findByIdAndUpdate(req.params.workId, {
$push: { "tags": { $each: newTags } }
})

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.

Complex Schema with subdocument

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.

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