Mongoose composite unique key index doesn't seem to work - javascript

I have added unique key index as suggested in the mongoose and mongoDB documentation but when I try to insert multiple question using insertMany it doesn't throw an error on duplicate items. Am I doing something wrong here?
Question.insertMany(questions);
const NotRequiredStringSchema = { type: String, required: false, default: '' };
const Question = new Schema({
"type": {
type: String,
trim: true,
enum: Object.values(questionTypes),
required: 'Question type is required'
},
"text": {
type: String,
required: true
},
"desc": NotRequiredStringSchema,
"options": [{
"id": ObjectId,
"name": NotRequiredStringSchema,
"helperText": NotRequiredStringSchema,
"icon_key": NotRequiredStringSchema,
"icon_url": NotRequiredStringSchema,
"icon_svg": NotRequiredStringSchema
}]
});
Question.index({
type: 1,
text: 1
}, {
unique: true
});
const model = mongoose.model('Question', Question);
module.exports = model;

Related

How to receive object information from within an array in mongoose?

I have two models, a posts model and a category model where I have an array that stores posts by objectId
Category Model
const mongoose = require('mongoose');
const CategorySchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
},
color: {
type: String,
required: true,
},
posts: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Post',
required: false,
}],
createdAt: {
type: Date,
default: Date.now,
}
},
{ timestamps: true }
);
module.exports = mongoose.model("Category", CategorySchema);
Post model
const mongoose = require('mongoose');
const PostSchema = new mongoose.Schema(
{
title: {
type: String,
required: true,
},
img: {
type: String,
required: true,
},
category: {
type: mongoose.Schema.Types.ObjectId,
ref: "Category",
},
desc: {
type: String,
required: false,
},
createdAt: {
type: Date,
default: Date.now,
}
},
{ timestamps: true }
);
module.exports = mongoose.model("Post", PostSchema);
So I created a get by id category controller
const Category = require('../../models/Category');
class FindCategory {
async find(req, res) {
const { id } = req.params;
try {
const category = await Category.findById(id);
return res.status(200).json(category);
} catch (err) {
return res.status(500).json(err);
}
}
}
module.exports = new FindCategory();
The problem is that when I make this request in my postman, it returns me for example
{
"_id": "63ac925d872445065a588f61",
"name": "Games",
"color": "#ff914d",
"posts": [
"63ac9cbccec4d9f35c4f4d1f"
],
"createdAt": "2022-12-28T19:00:45.847Z",
"updatedAt": "2022-12-28T19:49:47.119Z",
"__v": 0
}
But I would like to render the information of each post inside the "posts" array, something like that for example
{
"_id": "63ac925d872445065a588f61",
"name": "Games",
"color": "#ff914d",
"posts": [
"name": "red dead",
"img": "example.png",
"category": "games",
"desc": "test,
],
"createdAt": "2022-12-28T19:00:45.847Z",
"updatedAt": "2022-12-28T19:49:47.119Z",
"__v": 0
}
You should use the populate function provided by mongoose: https://mongoosejs.com/docs/populate.html#setting-populated-fields
Category.
findById(...).
populate('posts')

How to migrate old Mongoose Schema data to new Mongoose Schema Data

My previous Mongoose Schema is
social:{
instagram: String,
facebook: String,
whatsapp: String,
}
and my new Mongoose Schema is
social:{
instagram: {
data: String,
active: {
type: Boolean,
default: true
}
},
facebook:{
data: String,
active: {
type: Boolean,
default: true
}
},
whatsapp:{
data: String,
active: {
type: Boolean,
default: true
}
}
}
so basically in previous model I am storing link directly in variable like instagram,facebook,whatsapp
but in new model , I am storing link in data variable under main variable and adding addtional active variable , so how can I move previous around 20 data in new format of schema
You can do one update query that will transfer all documents to new structure. You can do it like this:
db.collection.update({
"social.instagram.active": {
"$exists": false
}
},
[
{
"$set": {
"social": {
"instagram": {
"data": "$social.instagram",
"active": true
},
"facebook": {
"data": "$social.facebook",
"active": true
},
"whatsapp": {
"data": "$social.whatsapp",
"active": true
}
}
}
}
],
{
"multi": true
})
Working example

Mongoose: res.json returns array with null records when "toObject" is used. Why and how can I solve this?

I'm currently trying to setup an API where I can fetch an array of objects that are assigned to a userId. I have defined the following Mongoose Model:
const userSchema = mongoose.Schema({
name: { type: String, required: true, trim: true },
email: { type: String, required: true, unique: true, trim: true },
password: { type: String, required: true, minlength: 6 },
engagements: [
{ type: mongoose.Types.ObjectId, required: true, ref: "Engagement" },
],
});
And have setup a controller like this:
exports.getEngsByUid = async (req, res, next) => {
const uid = req.params.uid;
let uidWithEngs;
try {
uidWithEngs = await User.findById(uid).populate("engagements");
} catch (err) {
const error = new HttpError("Fetching engagements failed!", 500);
return next(error);
}
if (!uidWithEngs || uidWithEngs.engagements.length === 0) {
return next(new HttpError("Could not find engagements for this user", 500));
}
res.json({
engagements: uidWithEngs.engagements.map((e) => {
e.toObject();
}),
});
};
The problem I am currently facing, is that when I send a GET requests to my defined path, I fetch an array of 'engagements' with null values:
{
"engagements": [
null,
null
]
}
However, if I remove the toObject method (and required .map method) and setup the res as follows:
res.json({
engagements: uidWithEngs.engagements,
});
I do get my array:
{
"engagements": [
{
"_id": "5fb47975eb319d24c098a06d",
"title": "testTitle1",
"client": "testClient1",
"year": 2030,
"owner": "5fb4795deb319d24c098a06b",
"__v": 0
},
{
"_id": "5fb4698aeb319d24c098a06f",
"title": "testTitle2",
"client": "testclient2",
"year": 2040,
"owner": "5fb4795deb319d24c098a06b",
"__v": 0
}
]
}
Why does the use of toObject() return an array with 2 null records and when I don't use the toObject() method, it returns 2 complete records? How can I solve this?
Thank you|
change res.json(...) to basically the short hand for arrow functions and it will work.

Mongoose populate does not populate array

I have struggled with the mongoose.model.populate function for hours now. I have even tried directly copying and pasting several solutions without luck.
I have a User model which is supposed to contain an array of 'Dilemmas' which he/she has created, but I have been unable to populate it.
Here are the models as well as the implementation of populate().
User.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
// Create Schema
const UserSchema = new Schema({
username: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
},
dilemmas: [
{
type: Schema.Types.ObjectId,
ref: "Dilemma"
}
]
});
module.exports = User = mongoose.model("User", UserSchema, "users");
Dilemma.js
const mongoose = require("mongoose");
const slug = require("mongoose-slug-generator");
const Schema = mongoose.Schema;
mongoose.plugin(slug);
// Create Schema
const DilemmaSchema = new Schema({
creator: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
title: {
type: String
},
slug: {
type: String,
slug: "title"
},
red: {
type: String,
required: true
},
blue: {
type: String,
required: true
},
red_votes: {
type: Number,
default: 0,
required: true
},
blue_votes: {
type: Number,
default: 0,
required: true
},
likes: [
{
user: {
type: Schema.Types.ObjectId,
ref: "User"
}
}
],
comments: [
{
user: {
type: Schema.Types.ObjectId,
ref: "User"
},
text: {
type: String,
required: true
},
author: {
type: String
},
avatar: {
type: String
},
date: {
type: Date,
default: Date.now
}
}
],
date: {
type: Date,
default: Date.now
}
});
module.exports = Dilemma = mongoose.model("Dilemma", DilemmaSchema, "dilemmas");
Routes.js
// #route GET api/users/profile
// #desc Gets logged in user's profile
// #access Private
router.get(
"/profile",
passport.authenticate("jwt", { session: false }),
(req, res) => {
User.find({ username: req.user.username })
.populate("dilemmas")
.then(user => {
if (!user) {
errors.nouser = "There is no user";
return res.status(404).json(errors);
}
res.json(user);
})
.catch(err => res.status(400).json(err));
}
);
JSON Response
[
{
"_id": "5b807beef770e7c7e6bf7ce0",
"dilemmas": [],
"username": "Jonas",
"email": "Mohrdevelopment#gmail.com",
"password": "$2a$10$QaqljS9x08YQ9N9EuCBTpO114ZJUFuVxAV80xMzImNi8eW2frPg0C",
"date": "2018-08-24T21:43:10.411Z",
"__v": 0
}
]
JSON Dilemmas response
[
{
"red_votes": 0,
"blue_votes": 0,
"_id": "5b80975f6e47fecba621f295",
"user": "5b807beef770e7c7e6bf7ce0",
"title": "Am i the real author asdsdasd?",
"red": "This is the red dilemma",
"blue": "This is the blue dilemma",
"likes": [],
"comments": [],
"date": "2018-08-24T23:40:15.381Z",
"slug": "am-i-the-real-author-asdsdasd",
"__v": 0
},
{
"red_votes": 0,
"blue_votes": 0,
"_id": "5b808e789bc36bcae8c6c3ad",
"creator": "5b807beef770e7c7e6bf7ce0",
"title": "Am i the real author?",
"red": "This is the red dilemma",
"blue": "This is the blue dilemma",
"likes": [],
"comments": [],
"date": "2018-08-24T23:02:16.565Z",
"slug": "am-i-the-real-author",
"__v": 0
}
]
JSON Users response
{
"_id": {
"$oid": "5b807beef770e7c7e6bf7ce0"
},
"dilemmas": [],
"username": "Jonas",
"email": "Mohrdevelopment#gmail.com",
"password": "$2a$10$QaqljS9x08YQ9N9EuCBTpO114ZJUFuVxAV80xMzImNi8eW2frPg0C",
"date": {
"$date": "2018-08-24T21:43:10.411Z"
},
"__v": 0
}
I just encountered a similar issue myself. Populating a ref worked, but populating an array of refs did not. I was able to get the array populate to work by explicitly specifying the model name in the populate call, e.g.:
User.find({ ... }).populate({
path: 'dilemmas',
model: 'Dilemma',
});
I don't know why this makes a difference, when the name of the referenced model is already specified in the schema.
Have you tried this?
User.find({ username: req.user.username })
.populate("dilemmas")
.exec() // <-- add exec() to perform the search
.then(user => {
...
})
Did you check the documentation here?
https://mongoosejs.com/docs/populate.html#refs-to-children
It shows a similar setup (with Authors and Stories.) It mentions 'pushing' stories to be able to use a find / populate combo.

How collection referencing works in mongoose?

First time i am trying to use refrence in mongoose , so i am trying to understand if i want to save template with user id , Do we need to get createdBy value from client or how it will be inserted into templateSchema. basically i want to save user id _id when user save template.I was able to save template but i did not get any error and createdBy property did not saved to template collection. Any layman explanation to understand refrencing in mongoose and how i can make it work with below code.
user.js
var UserSchema = new mongoose.Schema({
_id: { type: String, required: true, index: {unique: true}},
firstName: String,
lastName: String,
type: String,
groups:[{type: String, ref: 'Group', required: false}]
},
{
toObject: {
virtuals: true
},
toJSON: {
virtuals: true
}
});
template.js
var User = require('../user/user.model.js');
var TemplateSchema = new mongoose.Schema({
_id: { type: String, required: true},
name: String,
id: String,
appliesTo: [],
properties: [],
createdBy: { type: mongoose.Schema.Types.ObjectId, ref: 'User'}
});
templateCtrl.js
var eTemplate = require('./template.model');
var templatesJavaClass = {
"_id": 12586,
"name": "Java Class",
"id": "javaClass",
"appliesTo": [
"bpmn:UserTask"
],
"properties": [{
"label": "Java Package Name",
"type": "String",
"editable": true,
"binding": {
"type": "property",
"name": "camunda:class"
}
}],
"createdBy": "user1"
}
var template = new eTemplate(templatesJavaClass);
template.save(function(error){
console.log("successfully saved template");
if (error){
console.log(error);
}
});
You need to put user _id in createdBy field of template document while creating/saving it.
Also, make sure it is of Type ObjectId and not string. Otherwise you might get Cast Error.
Try this:
var templatesJavaClass = {
"_id": 12586,
"name": "Java Class",
"id": "javaClass",
"appliesTo": [
"bpmn:UserTask"
],
"properties": [{
"label": "Java Package Name",
"type": "String",
"editable": true,
"binding": {
"type": "property",
"name": "camunda:class"
}
}],
//save users _id in createdBy field
"createdBy": user1._id;//assuming user1 is the users document
}
var template = new eTemplate(templatesJavaClass);
template.save(function(error){
console.log("successfully saved template");
if (error){
console.log(error);
}
});

Categories

Resources