Mongoose: Check if value exists in string array - javascript

I am querying to get all articles that have a specific source name and category.
I have an article schema that looks like below.
The issue I'm facing is that, it fetches the articles with the correct source name, but it doesn't fetch for the right category. For example, if source is "cnn" and category is "sports", it fetches all articles from CNN correctly, but not with correct categories (the articles may have a categories of ['politics', 'culture'] with no sports)
const article_schema = new mongoose.Schema({
title: {
type: String,
required: true
},
thumbnail_url: {
type: String,
required: true
},
summary: {
type: String,
required: true
},
text: {
type: String,
required: true
},
link: {
type: String,
required: true
},
publish_date: {
type: String,
required: true
},
source: {
name: {
type: String,
required: true
},
name_slug: {
type: String,
required: true
},
link: {
type: String,
required: true
},
display_picture_url: {
type: String,
required: true
},
biography: {
type: String,
required: true
},
tags: {
type: [String],
required: true
},
rssFeeds: [{
url: {
type: String,
required: true
},
categories: {
type: [String],
required: true
}
}]
}
});
let getNews = async (req, res) => {
const { sort, filter, current_page, limit, category_slug } = req.body;
let articles = await Article.findOne({ 'source.name_slug': filter, categories: category_slug });
res.setHeader('Content-Type', 'application/json');
res.status(200).send({ articles });
}

Related

MongoDB Create New Document that references another Collection's Document IDs

I am trying to create a new document in the Form collection. This document references many FormSection documents. Here are the Schemas:
const FormSchema = new Schema({
title: {
type: String,
required: true,
unique: true
},
description: {
type: String,
required: true,
unique: true
},
sections: [{
type: FormSectionDetails
}],
createdDate: {
type: String,
required: false,
unique: true
},
lastEdited: {
type: String,
required: false,
unique: true
}
});
const FormSectionDetails = new Schema({
section: {
type: Schema.Types.ObjectId,
ref: 'FormSection',
required: true
},
position: {
type: Number,
required: true
}
});
const FormSectionSchema = new Schema({
name: {
type: String,
required: true,
unique: true
},
display: {
type: String,
required: true,
},
category: {
type: String,
required: true
},
...
});
let FormSection;
try {
FormSection = mongoose.connection.model('FormSection');
} catch (e) {
FormSection = mongoose.model('FormSection', FormSectionSchema);
}
However, when I try to add a new document to the Forms collection, I get an error:
Document being inserted:
formData = {
"title": "Returning Members",
"description": "Returning Members",
"sections":
[{
"section": "6292c0fbd4837faca1d85d4d",
"position": 1
},
{
"section": "6292c0fbd4837faca1d85d4e",
"position": 2
},
...
}
Code being run:
formdata.sections.map(s => {
return {
...s,
section: ObjectId(s.section),
}}
);
return await FormSection.create(formdata);
Error message:
ValidationError: category: Path `category` is required., display: Path `display` is required.````
Seems like it is trying to create a new FormSection document. I don't want it to create a new FormSection document. I just want it to reference existing FormSection documents using the Object IDs I specified.
The Issue seems to be with how you declare the section field in the FormSchema. Try this:
const FormSchema = new Schema({
title: {
type: String,
required: true,
unique: true
},
description: {
type: String,
required: true,
unique: true
},
sections: [{
type: ObjectId,
ref: 'FormSectionDetails',
required: true,
}],
createdDate: {
type: String,
required: false,
unique: true
},
lastEdited: {
type: String,
required: false,
unique: true
}
});
This would just store the _ids of the existing FormSectionDetails
It turns out I was inserting the document into the wrong collection. Instead of the code snippet:
return await FormSection.create(formdata);
It should actually be:
return await Form.create(formdata);
The error message should have been a more obvious hint for me as to what the problem was.

How to make a mongoose schema of arrays with nested subdocuments

I want to store an array of nested subdocuments such as the one down bellow:
[
{"2021-02-01income":{"value":37.95,"tax":0,"type":"income"}},
{"2021-03-01income":{"value":38.25,"tax":0,"type":"income"}},
{"2021-03-08fund": {"value":-78,"type":"fund","transaction":"610378deead56742a898443b"}},
{"2021-04-01income":{"value":38.53,"tax":0,"type":"income"}},
{"2021-07-01income":{"type":"income","tax":0,"value":134}},
]
I came up with the following schema which is not working, because as you can see the array of objects is based on unique keys nested objects...
Is there any workaround I can try:
const incomeSchema = mongoose.Schema({
type: { type: String, required: true },
value: { type: Number, required: true },
tax: { type: Number, required: false },
transaction: {
type: mongoose.Schema.Types.ObjectId,
required: false,
ref: 'Transaction',
},
});
const investmentSchema = mongoose.Schema(
{
incomes: [{ type: incomeSchema }],
name: { type: String, required: true },
user: {
type: mongoose.Schema.Types.ObjectId,
required: false,
ref: 'User',
},
account: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'Account',
},
broker: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'Broker',
},
type: { type: String, required: true },
rate: { type: String, required: true },
indexer: { type: String, required: true },
investment_date: { type: Date, required: true },
due_date: { type: Date, required: true },
initial_amount: { type: Number, required: true },
accrued_income: { type: Number, required: false, default: 0 },
taxes: { type: Number, required: false, default: 0 },
},
{ timestamps: true }
);
const Investment = mongoose.model('Investment', investmentSchema);
I found a workaround.... I just setted the _id in the Transaction schema as string and now everything is working... I mean I can update the array of neste subdocuments

Node Populate Array with object reference

I need to Populate courses of StudentSchema with the courses (Object_id) from CoursesSchema that belong to the major same as students major
let StudentSchema = new Schema({
_id: new Schema.Types.ObjectId,
emplId: {
type: Number,
required: true
},
major:{
type: String,
required: true
},
courses:[{
type: mongoose.Schema.Types.ObjectId,
ref: 'courses',
grade:{
type: String,
required: false,
}
}],
});
const courseSchema = new mongoose.Schema({
code: {
type: String,
required: true
},
title: {
type: String,
required: true
},
//array of majors that a courses is required for e.g: ['CS', 'CIS']
major: {
type: Array,
required: false,
},
//
CIS:{
type: Boolean,
required: false,
},
CNT:{
type: Boolean,
required: false,
},
CS:{
type: Boolean,
required: false,
},
GIS:{
type: Boolean,
required: false,
},
})
What do I do?
StudentCoursesRouter.get('/studentcourses', (req, res) => {
Courses.find({CS: true}, (err, courses) => {
if ( err ) {
console.log('Error occured while getting records');
res.json(err);
} else {
courseMap = {}
courses.forEach(function(course) {
courseMap[course._id] = course._id;
});
//res.send(courses);
Students.find({empleId: 12345678}).courses.push(courses);
}
res.json(Students);
})
This is what i am doing but it is not populating courses of student and gives an empty array for courses.
API Request Response Screenshot
You mention populate but you are not using populate?
e.g. Students.find({empleId: 12345678}).populate('course')
If you want it lean u also need to install mongoose-lean-virtuals
e.g. Students.find({empleId: 12345678}).populate('course').lean({ virtuals: true })

What's the difference between document.property and document.get('property')?

I have a mongoose document that has timestamps option enabled. I want to make decisions based on this timestamps but I noticed something weird according to my understanding.
I tried to get those values the traditional way (document.createdAt) but that returns undefined. But if I use document.get('createdAt') the value comes as in the database. The docs don't say anything about this. My question is: ¿Why timestamps behave this way?
Edit
The schema I'm using has an array of embedded schemas:
const Customer = new mongoose.Schema({
roles: {
type: [{
type: String,
enum: 'app b2b iot'.split(' '),
}],
default: 'app',
set: (value = []) => (value.includes('app')
? value
: value.concat('app')),
},
email: {
address: {
type: String,
trim: true,
lowercase: true,
set(email) {
this._previousEmail = this.email.address
return email
},
},
verified: {
type: Boolean,
},
token: String,
},
nickname: {
type: String,
trim: true,
},
recoveryToken: String,
gender: String,
birthday: String,
lastLogin: Date,
isAnonymous: {
type: Boolean,
default: false,
},
devices: [Device],
});
Device schema:
const Device = new mongoose.Schema({
customer: {
type: ObjectId,
ref: 'Customer',
required: true,
},
handle: {
type: String,
},
platform: {
type: String,
required: true,
set: toLowerCase,
},
info: Mixed,
smartFilterTags: [{
type: String,
}],
paidUntil: Date,
nh: {
tier: String,
_id: {
type: ObjectId,
},
location: {
type: {
type: String,
enum: ['Point'],
default: 'Point',
},
coordinates: [{
type: Number,
}],
},
})
I have a base plugin that apply when I compile models:
function basePlugin(schema) {
schema.add({
archivedAt: Date,
})
schema.set('timestamps', true)
schema.set('toJSON', {
virtuals: true,
})
schema.set('toObject', {
virtuals: true,
})
}

Updating nested array's field

I have a schema
const RoomSchema = mongoose.Schema({
title: {
type: String,
required: true
},
body: {
type: String,
required: true
},
author: {
type: String,
required: true
},
resource: {
type: String
},
posts: {
type: Array,
default: []
},
url: {
type: String
},
created_at: {
type: String,
required: true
}});
Field 'posts' is another document in my db, defined by the following schema:
const PostSchema = mongoose.Schema({
header: {
type: String,
required: true
},
body: {
type: String,
required: true
},
author: {
username: {type:String, required: true},
_id: {type:String, required:true}
},
room: {
type: String,
required: true
}});
So, I'm trying to create a query that would update fields of certain post inside posts array inside room. I've already tried suggested here, thought without results. I would appreciate any help on the subject
Room.update({ '_id': roomId, 'posts._id': postId },
{ $set: { 'posts.$.header': newHeader, 'posts.$.body': newBody } },
callback);

Categories

Resources