I have a really strange situtation; my schema has a fieldname which is called "type"
type: { type: String, default:"article" }
the schema is extended by subclasses which override the type field name to change the default value
when I create the document and directly after the cb fires, find it and output the result to console.log, I see "type" and the value "article" set as its value within the object.
when I access it with the mongo client, there is no field called "type". Getting just the type also doesn't show any document that have that field using this command
db.clouds.find({},{type:1}).pretty();
in a other script (that executes later), I get the document with mongoose again and there is also no "type" field there either.
Is "type" some special no-no word? My schema worked fine since ages and stopped working recently.
Thanks for your help
MongoDB: 2.4.9
Mongoose: 3.8.5
/edit, updated with real schema. My schema worked for a year until recently.
var Cloud = new Schema({
type :{ type:String, required:true },
children :[ { type:ObjectId } ], //Cloud ID
value :{ type: String, max:1024, default:function(){return "SomeRandomString" + Math.ceil(Math.random()*1000) } },
cats:[ {type: ObjectId} ]
},
{
collection:"clouds"
});
//make sure Mongooose provides the fields correctly;
Cloud.set('toJSON', { getters: true, virtuals: false } );
and subclassing like this (in another file, including the above file, thus making a new schema defininition)
var ArticleCloud=Cloud;
ArticleCloud.add(
{
type: { type: String, default:"article" },
url :{ type: String , index: true },
state: {type: Number, default: config.err[500].code, index: true },
weight:{type: Number, index:true}
}
);
Related
I have the following schema:
const { ObjectId } = Schema.Types
const Account = new Schema({
name: { type: String, required: true },
accountId: { type: String, required: true },
piracicaba: [{ type: ObjectId, ref: 'Piracicaba'}]
})
I know that by default MongoDB creates an _id property, but I would like to make accountId my default ID instead. Also, I would like to change that default generated string to a custom one.
How could I do that?
I have tried to change the accountId type to ObjectId:
const { ObjectId } = Schema.Types
const Account = new Schema({
name: { type: String, required: true },
accountId: { type: ObjectId },
piracicaba: [{ type: ObjectId, ref: 'Piracicaba'}]
})
But then when I try to store my customized ID mongoose throws BSONTypeError: Argument passed in must be a string of 12 bytes or a string of 24 hex characters or an integer.
My customized ID is from Oracle Cloud Account and it looks like this: ocid1.test.oc1..<unique_ID>EXAMPLE-compartmentId-Value
If you include an _id field in your schema definition, when you insert a document you must supply it with your own manually generated _id. If you don't, the document will not get inserted.
Alternatively, if you do not include an _id field in your schema definition, Mongoose will create this for you automatically, when the document is inserted, and it will be of type ObjectId (which is the default way that MongoDB sets the _id field on documents).
I hope this is the right place to discuss the CRUD issues. So I'm building a MERN e-commerce app, where I created the mongoose schema and connected with MongoDB to store the products & users. To test my schema and routes I used Postman, and while other requests related to users were working as usual I faced a weird error in the case of adding new products since this is the most important feature.
I'm not sure what is this error and why is this error occurring.
This is my POST request body -
const Product = require("../models/Product");
const router = require("express").Router();
// CREATE PRODUCT
router.post("/", verifyTokenAndAdmin, async (req, res) => {
const newProduct = new Product(req.body);
try {
const savedProduct = await newProduct.save();
res.status(200).json(savedProduct);
} catch (err) {
res.status(500).json(err);
}
});
The verifyToken is a JWT token.
Here is the Schema
const mongoose = require("mongoose");
const ProductSchema = new mongoose.Schema(
{
prodId: {
type: String,
required: true,
},
prodName: {
type: String,
required: true,
},
brandName: {
type: String,
required: true,
},
img: {
type: Array,
},
color: {
type: Array,
},
size: {
type: Object,
},
fabricSpecs: {
type: String,
},
model: {
type: String,
},
descDetail: {
type: String,
},
price: {
type: Number,
required: true
},
discount: {
type: Boolean
},
discountAmount: {
type: Number
},
rating: {
type: String
},
review: {
type: Number
},
soldOut: {
type: Boolean
},
category: {
type: String,
},
type: {
type: String,
}
},
{
timestamps: true,
}
);
module.exports = mongoose.model("Product", ProductSchema);
Here is the error shown in the Postman while adding creating another product
Tried mongo shell also but getting the same error
The error indicates an entry with {title: null} already exists for the index title_1. It is most likely a unique index and you need to adjust the title if entry item is a variant under the same title.
I am really grateful to Doug Duncan from the MongoDB community who helped me in figuring out the problem.
So the actual issue as described by Dough was that apparently, I was having a title field with a unique index that was being populated every time I was inserting a new document. Now for the first index, everything was fine and the document got inserted successfully but after that, all the inserts were throwing this title field null error shown below:
What I am seeing is that you have a unique index on the title field for the products collection. This is not getting populated so a null value is getting passed to the document and there is already a document with a null value in the collection. You have a unique index on the title based on the error you’re getting. Run db.products.getIndexes() and you should see the index.
Ironically, I haven't inserted any field named "title" anytime in my product schema, so how does this happen?
It turns out that MongoDB will allow you to create indexes on fields that don’t exist. It seems that somehow a unique index got created on the title field at some time even though no documents would contain that field. Now this can be fixed by dropping that index everything should be good and you will be able to insert more than a single document without the duplicate key violation.
So I ran the db.products.getIndexes() command in the mongo shell and found that he was right, there was actually a "title" field with a unique index value.
According to Dough, this can be fixed by removing the title field using this command
db.products.dropIndex({"title": 1})
Thanks to Dough, after running this command I can insert multiple documents since the title field is removed now and the only unique index is productId, which I make sure is always unique during insertion.
More about dropIndex -
https://www.mongodb.com/docs/v4.4/reference/method/db.collection.dropIndex/?_ga=2.253559119.714913216.1662801611-1986988651.1652705652
I currently have an DB that has optional parameter fields in the schema JSON objects. At the moment, when the fields are UPDATED from an existing value(whether that be string, date, or otherwise) to null, upon retrieving the object the field is not actually nulled. How do I modify these schema fields to allow certain fields (say, the last three) in the object to be nulled upon an update, and displayed as such upon a subsequent GET request? I've tried making the type an array and adding null, but that clearly is not correct. Ive also tried default: null but that also did not work.
data: {
// Mandatory params
name: { type: String, required: true, index: true },
id: { type: String, required: true },
type: { type: String, required: true },
// Optional params
parent: { type: db.objectId(), ref: 'organisation' }
parentSpid: { type: String },
memberStatus: { type: String },
memberTier: { type: String },
memberExpiry: { type: Date }
}
I assume you are using Mongoose to wrap mongo? Under the hood, your queries will be using the $set operator which explicitly does not overwrite fields without a new value.
You should use the $unset operator to nullify fields.
For example, if you wished to nullify parent you would do:
Model.findOneAndUpdate({ ...QUERY }, { $unset: { parent: 1 } });
The $unset object can contain any fields you wish to nullify. Be wary that validators don't always run on updates in Mongoose. See https://mongoosejs.com/docs/validation.html
How to update an array inside a mongoose schema with updateOne?
I have one model on my Node.Js application that I've made with mongoose schema.
One of the fields of my schema is an array:
guestsNames: []
I'm already able to save items inside of this array but I didn't find a way to update the items inside of it.
Here is my whole schema:
const screenImageSchema = mongoose.Schema({
company: {
type: String,
require: true,
trim: true
},
guestsNames: [],
imageName: {
type: String,
require: true
},
defaultImageName: {
type: String,
require: true
},
date: {
type: String,
default: Date.now,
require: true
},
activated: {
type: String,
default: 'Enabled'
},
wsType: {
type: String,
default: 'Image'
}
}, {timestamps: true});
...and my updateOne method:
screenImageSchema.methods.updateOne = function(id, screenImage) {
const updatedScreenImage = {
company: screenImage.company,
guestsNames: screenImage.guests,
imageName: screenImage.imageName,
defaultImageName: screenImage.defaultImageName,
date: screenImage.date,
activated: screenImage.activated,
wsType: screenImage.wsType
}
ScreenImage.updateOne(id, updatedScreenImage, {new: true});
}
The 'screenImage' parameter passed to the function is an object with all information that I need, including an array with all strings for guestsNames (I've already checked if the parameters are being passed correctly to the object and they are). All fields are being updated with this piece of code except the guestsNames field. What am I doing wrong and how can I make the guestsNames array be updated correctly?
Cheers.
You can update directly your array like this
ScreenImage.updateOne(id, { $set : { guestNames : newArray }})
You need to use $set to replace the value of a field, see this mongoDB $set
try this if it works
screenImageSchema.methods.updateOne = function(id, screenImage) {
const updatedScreenImage = {
company: screenImage.company,
guestsNames[0]: screenImage.guests,
imageName: screenImage.imageName,
defaultImageName: screenImage.defaultImageName,
date: screenImage.date,
activated: screenImage.activated,
wsType: screenImage.wsType
}
ScreenImage.updateOne(id, updatedScreenImage, {new: true});
}
I have the following schema:
entrySchema = new mongoose.Schema({
size: { type: Number },
title: {type: String, trim: true },
content: { type: String, trim: true },
tags: { type: [String], trim: true, index: true },
author: { type: String, trim: true, index: true }
});
entrySchema.index({ title: "text", content: "text" });
module.exports = mongoose.model('Entry', entrySchema);
The problem is that mongoose does not create the text indexes. The indexes for tags and author are created correctly, though.
Am I using the index() function in a wrong way?
I don't get any errors in the mongod session. It logs successful index creation for the non-text indexes, but it seems as if mongoose never calls ensureIndex for the text indexes.
After debugging as described in Mongoose Not Creating Indexes (thanks to #JohnyHK for the link) I saw that the actual problem was not the text index.
I was using the mongoose-auto-increment plugin and that resulted in errors indexing the _id field.
The solution was to have autoIncrement not use the _id field but a separate field like this:
entrySchema.plugin autoIncrement.plugin, {
model: 'Entry'
startAt: 1000
field: 'shortId'
}
I just did not thing about that because indexing worked fine without the text index. There seems to be some kind of incompatibility with the plugin and text indexes.