I have a simple help desk app I've been building, where user can make request for site changes. One of the features is being able to see all request made by a specific person, which is working. However on that page I wanted to have something akin to "User's Request" where user is the person's page you are on. However I can't seem to get it to work without some weird issues. If I use:
{{#each request}}
{{user.firstName}}'s Request
{{/each}}
It works but I end up with the header being written as many times as the user has request. However, when I tried:
{{request.user.firstName}}
It returns nothing.
My route is populating user data, so I think I should be able to reference it directly. Here's the route:
// list Request by User
router.get('/user/:userId', (req, res) => {
Request.find({user: req.params.userId})
.populate('user')
.populate('request')
.then(request => {
res.render('request/user', {
request: request,
});
});
});
Here's the schema:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Create Schema
const RequestSchema = new Schema({
title: {
type: String,
required: true,
},
body: {
type: String,
required: true,
},
status: {
type: String,
default: 'new',
},
priority: {
type: String,
default: 'low',
},
project: {
type: String,
default: 'miscellaneous',
},
category: {
type: String,
default: 'change',
category: ['change', 'bug', 'enhancement', 'investigation', 'minor_task', 'major_task', 'question'],
},
organization: {
type: String,
default: 'any',
},
assignedUser: {
type: String,
default: 'venkat',
},
allowComments: {
type: Boolean,
default: true,
},
user: {
type: Schema.Types.ObjectId,
ref: 'users',
},
lastUser: {
type: Schema.Types.ObjectId,
ref: 'users',
},
date: {
type: Date,
default: Date.now,
},
lastUpdate: {
type: Date,
default: Date.now,
},
comments: [{
commentBody: {
type: String,
required: true,
},
commentDate: {
type: Date,
default: Date.now,
},
commentUser: {
type: Schema.Types.ObjectId,
ref: 'users',
},
}],
});
// Create collection and add Schema
mongoose.model('request', RequestSchema);
The rest of the code is at: https://github.com/Abourass/avm_req_desk
If anyone is wondering how, the answer was to add the array identifier to the dot path notation:
<h4>{{request.0.user.firstName}}'s Request</h4>
Related
I have a Mongoose schema with an array lists of objects that consist of a reference to another collection and a nested array of numbers:
var Schema, exports, mongoose, schema;
mongoose = require("mongoose");
Schema = mongoose.Schema;
schema = new Schema({
name: {
type: String,
required: true,
unique: true,
trim: true
},
lists: [{
list: {
type: Schema.ObjectId,
require: true,
ref: "List"
},
allocations: [{
type: Number,
required: true
}]
}],
createdAt: {
type: Date,
"default": Date.now
},
updatedAt: {
type: Date
}
});
exports = module.exports = mongoose.model("Portfolio", schema);
However, I cannot get populate to work as expected without getting a TypeError: Cannot read property 'ref' of undefined. I've tried populate('list') and populate('lists list') but I'm either not calling things correctly or my Schema isn't formed correctly. I don't have this problem if I simply reference the lists by themselves:
lists: [{
type: Schema.ObjectId,
require: true,
ref: "List"
}]
but I want to have the allocations array alongside each list. What do I need to do to get the behavior I want?
I found the answer: populate('lists.list') works. Thanks to this question: Mongoose populate within an object?
Actual answer:
Use this,
populate('lists.list')
Extra:
Here are lists are an array of objects (list).
In JS you can access this like that,
console.log(lists.list);
and MongoDB syntax is 99% similar to JS syntax.
so....................
lists: [{
list: {
type: Schema.ObjectId,
require: true,
ref: "List"
},
allocations: [{
type: Number,
required: true
}]
}],
=> Because it's an array of objects, you can do this -: Portfolio.populate('lists.list');
2.
lists: [{
type: Schema.ObjectId,
require: true,
ref: "List"
}]
=> Because it's an array, you just have to do this -: Portfolio.populate('lists');
if you have nested schema
YourSchema.find()
.populate({
path: 'map_data',
populate: {
path: 'location'
}
})
it's work for me
// Cart schema
var CartSchema = new mongooseSchema({
productDetails: [{
productId: {
type: mongoose.Schema.ObjectId,
required: true,
ref: 'Product'
},
productCount: Number,
}],
UserId: {
type: String,
default: '',
required: true,
trim: true,
},
shopId: {
type: String,
default: '',
required: true,
trim: true,
},
});
// add this .populate('productDetails.productId').
db.Cart.find({
UserId: userId,
shopId: shopId
}).populate('productDetails.productId')
.skip(pagination.skip)
.limit(pagination.limit)
.exec(function(error,
CartList) {
if (error) {
callback(error, null)
} else {
callback(null, CartList)
}
});
Populate didn't work in my case when nesting to array my Schema was
const chatSchema = mongoose.Schema({
chats: [{
type: Schema.Types.ObjectId,
ref: "ChatMsg"
}],
})
How I solved it
Chat.findOne({
customer: req.body.customer,
agency: req.body.agency
}, (err, chat) => {
if (err) {
res.status(422).send("Our fault");
}
chat.populate("chats").execPopulate(() => {
res.send(chat);
});
});
I am trying to display all the data with the "populate" statement. But I only get one "populate" but when I put many it doesn't work.
what I want to do is to bring me the data from the "User", "Customer" model as well.
This is my code
My Model:
import { model, Schema } from 'mongoose';
const RoomSchema = new Schema({
Users: [
{
agentId: {
type: Schema.Types.ObjectId,
ref: "User",
required: false,
},
customerId: {
type: Schema.Types.ObjectId,
ref: "Customer",
required: false,
},
typeId: Number, // 1 - agent, 2 - client
},
],
Messages: [
{
agentId: {
type: Schema.Types.ObjectId,
ref: "User",
required: false,
},
customerId: {
type: Schema.Types.ObjectId,
ref: "Customer",
required: false,
},
message: {
type: String,
required: true,
},
date: Date,
sender: Number,
},
],
FinishAt: Date,
FinishBy: String,
typeFinishBy: Number, // 1 - agent, 2 - client
}, {
timestamps: true,
versionKey: false
});
export default model('Room', RoomSchema);
this is the sentence I am using
import Room from "../models/Room.js";
async function getOnlyRoom(id) {
const foundRoom = await Room.findById(id)
.populate('Users.agentId')
.populate('Users.customerId')
.populate('Messages.agentId')
.populate('Messages.customerId')
.execPopulate();
return foundRoom
}
Image of Json Postman
only works with one
foundRoom.populate('Users.customerId')
Works with only populate
this is the error
image of error
Thank you very much for your help
I have found the solution to my problem
I was researching the solution on the mongoose website and did it with a single populate.
const populateRoom = await foundRoom
.populate([
{ path: 'Users.agentId', select: 'name' },
{ path: 'Users.customerId', select: 'name' },
{ path: 'Messages.agentId', select: 'name' },
{ path: 'Messages.customerId', select: 'name' }
])
return populateRoom;
I am making a forum app that is quite similar to Reddit. I am using mongoose here for schema design. I have some doubts regarding models that I have- User, Post and Comment.
Does the schema look all right of all the models?
In User, I want to show the friends on the user profile. Like when you go to his profile, there will be like Friends(200), and when I click the friend list will appear(like Facebook, then on clicking you can access friends' profiles). I haven't created Friend schema, but does it needed actually?
Question about comments. So far, I have the basic comment schema. What happens to the threaded comments or replies. How do I store them?
All the models that I have currently:
const userSchema = new Schema(
{
username: { type: String, required: true },
email: { type: String, reuired: true },
password: { type: String, required: true },
country: { type: String, required: true },
friends: [{ type: Schema.Types.ObjectId, ref: "Friend" }], // is it needed?
posts: [{ type: Schema.Types.ObjectId, ref: "Post" }],
},
{ timestamps: true }
)
const postSchema = new Schema(
{
title: { type: String, required: true },
description: { type: String, required: true },
user: { type: Schema.Types.ObjectId, ref: "User" },
slug: { type: String, slug: "title" },
upvotes: { type: Number },
downvotes: { type: Number },
city: { type: String }, // post will have a tag by the city like NewYork, LA etc.
},
{ timestamps: true }
)
const commentSchema = new Schema(
{
comment: { type: String, required: true },
post: { type: Schema.Types.ObjectId, ref: "Post"},
user: { type: Schema.Types.ObjectId, ref: "User"},
upvotes: { type: Number },
downvotes: { type: Number }
},
{ timestamps: true }
)
For the Second Question you don't need friend schema since friend is also a user.
For the first question, Why do intend to store all the posts of a user inside the User object as a list of posts, this would mean fetching 100s of posts even when something basic like username or email is required. Instead, you can place user_id in the Post Schema, helping to identify posts from a particular User.
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,
})
}
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);