I am trying to insert a subdocument using .create() and also query said document using .id(). I've been following the guide here
I am getting the error: object has no method 'id()' or 'create()'
The following is my code:
/db/schemas/AnnouncementsSchema.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var postSchema = new Schema({
title: String,
dateCreated: String,
dateEdited: { type: Date, default: Date.now() },
summary: String,
body: String
});
var announcementsSchema= new Schema({
categoryName: String,
posts: [postSchema]
});
announcementsSchema.methods.Update = function (callback) {
console.log('Updating object: ' + this);
this.save(function (err, object) {
callback(err, object);
});
}
var announcements = mongoose.model('announcements', announcementsSchema);
var post = mongoose.model('post', postSchema);
module.exports = {
announcements: announcements,
post: post
};
/routes/Announcements.js
var mongoose = require('mongoose');
var announcementsSchema = require('../../db/schemas/AnnouncementsSchema.js');
exports.InsertPost = function (req, res) {
var announcements = announcementsSchema.announcements;
var post = announcementsSchema.post;
var categoryToEdit = req.body.categoryToEdit;
var newPost = req.body.newPost;
announcements.GetById(categoryToEdit._id, function (err, announcment) {
var postToAdd = new post(newPost);
announcment.posts.create(postToAdd);
announcment.Update(function (err, object) {
res.send({ err: err, data: object});
});
});
}
I have the .save method wrapped so I can add extra functionality if needed. I crashes when it calls .create(). The same is true if I am trying to remove a post as well. Here is the code for that:
exports.DeletePost = function (req, res) {
var announcements = announcementsSchema.announcements;
var categoryId = req.body.categoryId;
var postId = req.body.postId;
announcements.findById(categoryId, function (err, object) {
var postToDelete = object.posts.id(postId);
console.log(postToDelete);
res.end();
});
}
Either way they both crash and google is pretty slim on answers. Most people have given a of different ways to expose the schemas and models, and what I have above is pretty much a sum of what they suggested. Any ideas? Thanks!
I found the answer after toying with this forever. It was simple. The order in which you declare your schema matters. So I had to declare my subdocument schema before I declare my parent schema. Such as:
var announcementsSchema= new Schema({
categoryName: String,
posts: [postSchema]
});
var postSchema = new Schema({
title: String,
dateCreated: String,
dateEdited: { type: Date, default: Date.now() },
summary: String,
body: String
});
This worked! I am now able to keep all the rest of the code the same, but now the methods exist!
Even if I recently picked up Express.js, I will do my best in trying to provide a useful answer. Hope it helps!
If you want to access the id of a particular post, it is stored in the ._id property, not id. Moreover, I believe that you first have to loop over object.posts since it is an array of posts:
exports.DeletePost = function (req, res) {
var announcements = announcementsSchema.announcements;
var announcementId = req.body.announcementId;
var postId = req.body.postId; // This is the _id property of an element contained within the posts array
var postToDelete = {};
announcements.findById(announcementId, function (err, object) {
// Get the posts array
var posts = object.posts;
// Loop over it until you find the post with the id that you stored in postId
for (var i = 0; i < posts.length; i ++) {
if (posts[i]._id == postId) {
postToDelete = posts[i];
}
}
console.log(postToDelete);
res.end();
});
}
As for your InsertPost function, you should also take into account the fact that posts is an array. Hence, you could simply push the new post into that array and save it accordingly:
exports.InsertPost = function (req, res) {
var announcements = announcementsSchema.announcements;
var post = announcementsSchema.post;
var announcementId = req.body.announcementId;
var newPost = req.body.newPost;
announcements.findById(announcementId, function (err, announcment) {
var postToAdd = new post(newPost);
announcment.posts.push(postToAdd);
announcment.save(function(err) {
if (err) {
res.send(500, { error: err.stack });
}
console.log('Success');
res.end();
});
});
}
Related
I am trying to update sub documents with mongoose using the request.body without passing of the sub documents _id. Updating works but mongoose is removing the _id from the sub documents.
Assume the following schemas
// schemas.js
const mongoose = require('mongoose');
const motorSchema = new mongoose.Schema({
type: String,
volume: Number,
});
const carSchema = new mongoose.Schema({
manufacturer: String,
model: String,
motors: [motorSchema],
});
const userSchema = new mongoose.Schema({
username: String,
email: String,
cars: [carSchema]
});
const mongoose = require('mongoose');
// import schemas
const userSchema = require('userSchema');
const carSchema = require('carSchema');
const motorSchema = require('motorSchema');
// create models
const User = mongoose.model("User", userSchema);
const Car = mongoose.model("Car", carSchema);
const Motor = mongoose.model("Motor", motorSchema);
module.exports.updateCar = async function (request, response) {
const condition = {
_id: new mongoose.Types.ObjectId(request.body.userId),
"cars._id": new mongoose.Types.ObjectIt(request.body.carId)
};
// Build object for partial update
const set = {};
for(let field in reqest.body){
set[`cars.$.${field}`] = request.body[field];
}
const update = {
$set = set;
}
User.findOneAndUpdate(condition, update, {new: true, overwrite: false},
(error, user) => {
if(error) {response.send(error)}
response.json(user);
}
}
The problem is that all my _id properties will be overwritten in the motors array. How can I force mongoose as default to not change the _id properties?
If I understand you correctly, the equivalent mongoDB syntax will use arrayFilters, so you can modify your query to use that as well:
For example:
User.findOneAndUpdate(
condition,
{$set: {"cars.$[item].size": "large"}},
{arrayFilters: [{"item._id": new mongoose.Types.ObjectIt(request.body.carId)}]}
)
See how it works on the playground example
According to this method, your code needs the arrayFilters in the options part and the $[<identifier>] in the $set part of the query:
const set = {};
for(let field in reqest.body){
set[`cars.$[item].${field}`] = request.body[field];
}
const update = {
$set = set;
}
User.findOneAndUpdate(
condition,
update,
{
arrayFilters: [{"item._id": new mongoose.Types.ObjectIt(request.body.carId)}],
new: true, overwrite: false
},
(error, user) => {
if(error) {response.send(error)}
response.json(user);
}
I'm trying to push data to a nested array in mongodb. I'm using mongoose as well.
This is just mock code to see if i can get it working:
User model:
import mongoose from "mongoose";
const CoinSchema = new mongoose.Schema({
coinID: { type: String },
});
const CoinsSchema = new mongoose.Schema({
coin: [CoinSchema],
});
const WatchlistSchema = new mongoose.Schema({
watchlistName: { type: String },
coins: [CoinsSchema],
});
const NameSchema = new mongoose.Schema({
firstName: { type: String },
lastName: { type: String },
username: { type: String },
});
const UserSchema = new mongoose.Schema({
name: [NameSchema],
watchlists: [WatchlistSchema],
test: String,
});
const User = mongoose.model("User", UserSchema);
export default User;
route:
fastify.put("/:id", async (request, reply) => {
try {
const { id } = request.params;
const newCoin = request.body;
const updatedUser = await User.findByIdAndUpdate(id, {
$push: { "watchlists[0].coins[0].coin": newCoin },
});
await updatedUser.save();
// console.dir(updatedUser, { depth: null });
reply.status(201).send(updatedUser);
} catch (error) {
reply.status(500).send("could not add to list");
}
});
request.body // "coinID": "test"
I've tried a lot of different ways to push this data but still no luck. I still get 201 status codes in my terminal which indicates something has been pushed to the DB, but when I check nothing new is there.
Whats the correct way to target nested arrays and push data to them?
It's not perfect but you could get the user document, update the user's watchlist, and then save the updated watchlist like so:
fastify.put("/:id", async (request, reply) => {
try {
const { id } = request.params;
const newCoin = request.body;
// get the user
let user = await User.findById(id);
// push the new coin to the User's watchlist
user.watchlists[0].coins[0].coin.push(newCoin);
//update the user document
const updatedUser = await User.findOneAndUpdate({ _id: id },
{
watchlists: user.watchlists,
},
{
new: true,
useFindAndModify: false
}
);
reply.status(201).send(updatedUser);
} catch (error) {
reply.status(500).send("could not add to list");
}
});
this is a very odd one that I don't quite understand why it's not working. I have 2 functions, one to add an item to a MongoDB collection. That is working fine. I have another function which is meant to search the collection for items matching my query. For some reason, the search function is returning 'not a function' and I'm wondering if anyone can help?
When I try and call findSimilarEvents() I get TypeError: event.find is not a function back in the console
My model:
var mongoose = require('mongoose');
const eventSchema = new mongoose.Schema({
eventTime: { type: Date, default: Date.now() },
eventLoggedFrom: String,
eventData: Object,
eventID: String,
ticketID: { type: String, default: "" },
ticketStatus: { type: String, default: "" },
eventLastUpdated: { type: Date, default: Date.now() },
})
module.exports = mongoose.model('event', eventSchema);
My working function:
exports.addEventToDB = async function(eventData, eventLoggedFrom, EventID) {
const event = new EventModel({
eventLoggedFrom: eventLoggedFrom,
eventData, // this is a JSON object
eventID: eventID
});
await event.save();
}
My non-working function:
exports.findSimilarEvents = async function(eventData, eventLoggedFrom) {
const event = new EventModel();
let similarEvents = await event.find({
eventData: eventData
});
for (var i = 0; i = similarEvents.length; i++) {
console.log("found similar event");
console.log(similarEvents[i]);
}
}
I'm happy to provide any other info if anyone has any thoughts!
Thank you in advance
exports.findSimilarEvents = async function(eventData, eventLoggedFrom) {
let similarEvents = await EventModel.find({
eventData: eventData
});
for (var i = 0; i = similarEvents.length; i++) {
console.log("found similar event");
console.log(similarEvents[i]);
}
}
try this ...
I have used the below code in my API to remove element from an array
deleteCommentLike: async(req, res) => {
const { error } = createComLikeValidation(req.body);
if (!error) {
const { user_id, comment_id } = req.body;
// const likeModel = new likeSchemaModel({user_id: user_id, post_id: post_id});
await commentlikeSchemaModel
.find({ user_id: user_id, comment_id: comment_id })
.remove();
let commenttData = await commentSchemaModel.findById(comment_id);
console.log(commenttData.usersLiked);
commenttData.likes = --commenttData.likes;
commenttData.usersLiked.remove(user_id);
await commenttData.save();
res.status(200).json({ error: false, data: "done" });
} else {
let detail = error.details[0].message;
res.send({ error: true, data: detail });
}
},
In here this one line is not working: commenttData.usersLiked.remove(user_id);. It doesn't give any error but the user_id is not removed from my database.
"use strict";
const mongoose = require('mongoose');
const Joi = require('joi');
var commentSchema = mongoose.Schema({
//other data
usersLiked: [{
type: mongoose.Types.ObjectId,
default: []
}],
//other data
}
var commentSchemaModel = mongoose.model('comments', commentSchema);
module.exports = {
commentSchemaModel,
}
In my mongodb it looks like below
I have alredy tried using it as commenttData.usersLiked.remove(mongoose.Types.ObjectId('user_id'));
but the result is same.
What can be the reason for this and how could I remove the value from the array ?
You should use an update operation:
commenttData.update({_id: mongoose.Types.ObjectId("5f099..")}, {$set: {usersLiked: yourUpdatedUsersLikedArray}})
The error you expect from remove() is missing as you trigger a js noop which is just ignored by the compiler.
Mongoose does not implement the attribute update operation the way you use it.
I have defined a schema for add question and its like
var mongoose = require('mongoose');
var questionSchema = new mongoose.Schema({
question_set : String,
questions:[{
question_id : String,
question_no : Number
}]
});
I would like to insert variables say, ques_set = 'xyz' and an array question_array = [['id_1',1],['id_2',2],['id_3',3]].
I used this code to insert to mongodb
var questions = require('../schemas/questions');
exports.testing = function(req,res){
if (!req.body) return res.sendStatus(400)
var ques_set = 'xyz';
var question_array = [['id_1',1],['id_2',2],['id_3',3]];
var data = question({ques_set,question_array);
data.save(function(err) {
if (err) throw err;
else {
console.log('Question Inserted');
res.send("Question Inserted");
}
});
};
This shows me an error TypeError: object is not a function. Please help me, I just started nodejs. Thanks
You need to create a question object that matches your schema, something like this:
var Question = require('../schemas/questions');
exports.testing = function(req,res){
if (!req.body) return res.sendStatus(400)
var ques_set = 'xyz';
var question_array = [
{
question_id: "id_1",
question_no: 1
},
{
question_id: "id_2",
question_no: 2
},
{
question_id: "id_3",
question_no: 3
}
];
var data = Question({question_set: ques_set, questions: question_array});
data.save(function(err) {
if (err) throw err;
else {
console.log('Question Inserted');
res.send("Question Inserted");
}
});
};