I have a comments field in my interface and schema as follows
export interface Blog extends Document {
...
comments: { user: ObjectId; comment: string }[]
...
}
const blogSchema = new Schema<Blog>({
...
comments: [
{
user: {
type: ObjectId
},
comment: {
type: String
}
}
],
...
})
However, schema throws this error 'ObjectId' only refers to a type but is being used as a value here.. I know that schema is written kind of in a weird way, but I'm confused with how to improve.
What I want in database is something like
[
{
user: "Vivid",
comment: "Vivid's comment"
},
{
user: "David",
comment: "David's comment"
}
]
I believe you need to change ObjectId to
mongoose.Schema.Types.ObjectId
Either that, or you could do something like:
const mongoose = require('mongoose');
// ... other imports
const { ObjectId } = mongoose.Schema.Types;
// ... now use in code as `ObjectId`
Related
I'm trying to remove all of strings that match occurrences in the array of 'interestedStudents' in a Mongoose schema.
My Mongoose schema looks like this:
// Create a schema.
const schema = new mongoose.Schema<Post>({
interestedStudents: {
type: [{
type: String,
unique: true
}],
required: false,
},
})
//Create model
export const PostModel = model<Post>('Post', schema);
I'm trying to remove by using:
await PostModel.updateMany({ interestedStudents: { $pullAll : [userId]}})
But I'm getting the following error:
"CastError: Cast to [string] failed for value "[ { '$pullAll': [ '62854109cf9a6db1fcf0393b' ] } ]" (type string) at path "interestedStudents.0" because of "CastError"\n at model.Query.exec
What am I doing wrong? Is my Schema set up wrong? Maybe it's not an array of string?
It was as easy as this for anyone else coming here:
const { modifiedCount } = await PostModel.updateMany({}, { $pull: { interestedStudents: userId } })
Is there any way to query inside this struture by the object keys of roles?
interface UsersModel{
_id: string;
email: string;
roles: { [key: string]: RolesType[] };
}
For now I get the data into users like:
roles: {
$ne: null
}
and then
const finalResult = users.filter(u => Object.keys(u.roles).includes('objectKeyIwant'));
Can this be done on the mongodb side and avoid getting all the data then filter it?
Data examples:
The user collection is like this:
{
_id: '610baff85c071a2bd59dc84f',
email: 'some#email.com',
roles : {
"shop1" : [
"shop_stock_manager"
],
"shop2" : [
"shop_admin",
"shop_stock_manager"
]
}
}
And I want to get all the users that have any role in shop2.
use this
db.collection.find({"roles.shop2":{$ne:[]}})
I am making a blog service using express and apollo-express along with mongodb (mongoose).
I made some mutation queries, but I have no success with obtaining the args of a mutation query.
Now I am asking for how I should structure my mutation query in order to make the thing work. thanks.
error:
"message": "Blog validation failed: title: Path title is required., slug: Path slug is required."
the query:
mutation ($input: BlogInput) {
newBlog(input: $input) {
title
slug
}
}
the query variables:
{
"input": {
"title": "ABC",
"slug": "abc"
}
}
part of my graphql schema:
type Blog {
id: ID!
title: String!
slug: String!
description: String
users: [User]!
posts: [Post]!
}
input BlogInput {
title: String!
slug: String!
description: String
}
extend type Mutation {
newBlog(input: BlogInput): Blog
}
part of my resolvers:
import Blog from './blog.model'
export const blogs = async () => {
const data = await Blog.find().exec()
return data
}
export const newBlog = async (_, args) => {
const data = await Blog.create({ title: args.title, slug: args.slug })
return data
}
part of my database schema (mongoose):
import mongoose from 'mongoose'
const Schema = mongoose.Schema
const blogSchema = Schema({
title: {
type: String,
required: true
},
slug: {
type: String,
required: true,
unique: true
},
description: {
type: String
},
users: {
type: [Schema.Types.ObjectId],
ref: 'User'
},
posts: {
type: [Schema.Types.ObjectId],
ref: 'Post'
}
})
export default mongoose.model('Blog', blogSchema)
You've defined your newBlog mutation to accept a single argument named input. From what I can tell, you're correctly passing that argument to the mutation using a variable. Your resolver receives a map of the arguments passed to the field being resolved. That means you can access individual properties of the input object like this:
export const newBlog = async (_, args) => {
const data = await Blog.create({ title: args.input.title, slug: args.input.slug })
return data
}
Note, you may want to make input non-nullable (i.e. set the type to BlogInput!), otherwise your resolver will need to handle the possibility of args.input returning undefined.
I have the following schema:
const userSchema = new mongoose.Schema({
profile: {
name: {
type: String,
default: "",
enum: ["", "Mike", "John", "Bob"]
}
}
}
I would like to ensure that when a user.save action is triggered and provided name variable is not in the list of available enum values, validation does not fail, but sets the value to default.
For example, in Node:
User
.findById(req.user.id)
.then(user => {
user = Object.assign(user, { name: "Sam" })
return user.save()
})
This will fail validation with Sam is not a valid enum value for path profile.name, but the ask is to have value fallback to an empty string:
{
name: ""
}
I tried tapping into Mongoose pre validate hook, but cannot seem to access provided values and documentation has not been helpful.
maybe you can use a pre save hooks
var schema = new Schema(..);
schema.pre('save', function(next) {
// verify here
next();
});
A user has project IDs but I also want to store some additional project info:
const userSchema = new Schema({
...
projects: [{
_id: {
type: Schema.Types.ObjectId,
ref: 'Project',
unique: true, // needed?
},
selectedLanguage: String,
}]
});
And I want to populate with the project name so I'm doing:
const user = await User
.findById(req.user.id, 'projects')
.populate('projects._id', 'name')
.exec();
However user.projects gives me this undesirable output:
[
{
selectedLanguage: 'en',
_id: { name: 'ProjectName', _id: 5a50ccde03c2d1f5a07e0ff3 }
}
]
What I wanted was:
[
{ name: 'ProjectName', _id: 5a50ccde03c2d1f5a07e0ff3, selectedLanguage: 'en' }
]
I can transform the data but I'm hoping that Mongoose can achieve this out the box as it seems a common scenario? Thanks.
Seems like there are two options here:
1) Name the _id field something more semantic so it's:
{
selectedLanguage: 'en',
somethingSemantic: { _id: x, name: 'ProjectName' },
}
2) Flatten the data which can be done generically with modern JS:
const user = await User
.findById(req.user.id, 'projects')
.populate('projects._id', 'name')
.lean() // Important to use .lean() or you get mongoose props spread in
.exec();
const projects = user.projects.map(({ _id, ...other }) => ({
..._id,
...other,
}));
try something like this
populate({path:'projects', select:'name selectedLanguage'})