mongoose, trying to find one object by a value - javascript

What I'm trying to accomplish here is to find one object by a value, and then adding that object to another objects property.
Code
q = {
_id: Schema.Types.ObjectId,
category: QuestionCategory,
question: String,
name: String,
};
QuestionCategory.findOne().sort({ category: "ExampleCategory" }).exec((err, doc) => {
if(err)
{
return err
}
q.category = doc;
})
error:
throw new TypeError('Invalid sort value: {' + field + ': ' + value + ' }');
^
TypeError: Invalid sort value: {category: ExampleCategory }
I've also tried without the .sort and write the filter inside findOne, but didn't work either
The Schema
const QuestionCategorySchema= new Schema({
_id: Schema.Types.ObjectId,
category: String,
icon: String,
order: Number
}, { collection: 'QuestionCategory' });

if you are trying to query the documents with category field ExampleCategory you need to make a find query not a sort query
and also there is no need of sorting the data when your are using findOne as it only gets one QuestionCategory
QuestionCategory.findOne({category:"ExampleCategory"}).exec(err, doc)=>{})

The first thing you can't use sort() like this sort({ category: "ExampleCategory" }), You need to sort like
.sort({ category: -1 }) OR .sort({ category: 1 }), Another thing we can't use sort() while performing top fetch a single record from database(Ex.findOne()). The sort() basically used for sorting your data respectively your keys. By the way you can get your desired result by below query:
QuestionCategory.find({}).sort({ _id: -1 }).limit(1)

Related

Is there a way to update an object in an array of a document by query in Mongoose?

I have got a data structure:
{
field: 1,
field: 3,
field: [
{ _id: xxx , subfield: 1 },
{ _id: xxx , subfield: 1 },
]
}
I need to update a certain element in the array.
So far I can only do that by pulling out old object and pushing in a new one, but it changes the file order.
My implementation:
const product = await ProductModel.findOne({ _id: productID });
const price = product.prices.find( (price: any) => price._id == id );
if(!price) {
throw {
type: 'ProductPriceError',
code: 404,
message: `Coundn't find price with provided ID: ${id}`,
success: false,
}
}
product.prices.pull({ _id: id })
product.prices.push(Object.assign(price, payload))
await product.save()
and I wonder if there is any atomic way to implement that. Because this approach doesn't seem to be secured.
Yes, you can update a particular object in the array if you can find it.
Have a look at the positional '$' operator here.
Your current implementation using mongoose will then be somewhat like this:
await ProductModel.updateOne(
{ _id: productID, 'prices._id': id },//Finding Product with the particular price
{ $set: { 'prices.$.subField': subFieldValue } },
);
Notice the '$' symbol in prices.$.subField. MongoDB is smart enough to only update the element at the index which was found by the query.

Inserting multiple ObjectIds to sub-document at once with mongoose

I'm using mongoose and I have the following model:
const UniversitySchema = new Schema({
name: {
type: String,
required: [true, 'Name is required']
},
color: {
type: String
},
paths: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Path'
}]
})
I want to be able to insert multiple paths (which cast to the Path model) into the universities collection when first creating it. I tried the following code:
const newUni = new University({
name: name,
paths: [...pathIds],
color: color
})
newUni.save()
.then(uni => {
return res.send(uni)
})
.catch(err => console.log(err));
})
However it raises this error:
CastError: Cast to ObjectId failed for value "[ 5f122f9967c59932b44214b6, 5f2762858f9060327c4f6b2f ]" at path "_id" for model "Path"
messageFormat: undefined,
stringValue: '"[ 5f122f9967c59932b44214b6, 5f2762858f9060327c4f6b2f ]"',
kind: 'ObjectId',
value: [ 5f122f9967c59932b44214b6, 5f2762858f9060327c4f6b2f ],
path: '_id',
reason: Error: Argument passed in must be a single String of 12 bytes or a string
of 24 hex characters
It looks like mongoose does not cast the Ids separately when there are more than one, because when I tried it with one id, it worked.
I also tried to save the documents and then push the ids to the path array, but it didn't work.
Is there a way to do it all at once?
Thanks in advance.
You need to make sure that there are no whitespaces in each of the array's id- values:
With this code
const newUni = new University({
name,
paths: ["5f122f9967c59932b44214b6","5f2762858f9060327c4f6b2f"],
color
})
it should definitely work.
So assuming pathIds initially holds the string " 5f122f9967c59932b44214b6, 5f2762858f9060327c4f6b2f ", you can simply do
...
paths: pathIds.split(",").map(v => v.trim()),
...
to get an array of the trimmed id-values:

How can I reverse the order of items returned from Model.find({});

This command
Model.find({});
is used by Mongoose go return all the models of type Model. However whenever I display the array of JSON that it is returned it is in reverse order.
I could just loop through the array backwards but was curious if there is a way to have Mongoose return the array so that the last model I added would be the first returned.
Thanks.
You need to use sort on the published date. How i did
vObj
.find()
.sort({ publishedAt: "-1" })
.limit(50)
.then((videos) => {
//skip it
})
You need to add timestamp to your model.This is how i did.
var videoSchema = new mongoose.Schema({
title: { type: String, required: true, },
description: String,
imageurl:{type:String,required:true,},
publishedAt:{type:String,required:true,},
},{ timestamps: true });

return single object based on ObjectId

hi im currently building something for fun that allows users to post anything. and im experincing some problems here is my code.
return details.findOne({'data': {$elemMatch: {'_id':req.params.id}}}).then((a) => {
return res.render('post', { a });
}).catch(err => console.log(err));
i only want this to return one post i thought by using the objectId id would be able todo that but it seems to return everything in the data array anybody have any ideas below is my schema.
i need this to only return the single object whos objId is in the url
var schemaMode = new mongoose.Schema({
email: {type: String, required: true},
password: {type: String, required: true},
username: {type: String,required:true},
data: [{
author: String,
title: String,
comments: [String],
article: String,
}]
});
Details.findById(req.params.id, function(err, foundObject){
//foundObject contains the object with the ._id matching req.params.id
});
if you only want certain fields back, like you want the object to only have its data field for example, then you do:
Details.findById(req.params.id, "data",
function(err, foundObject){
//foundObject contains the object with the ._id matching req.params.id
});
OR
Details.findById(req.params.id).select("data")
.exec(function(err, foundObject){
//foundObject contains the object with the ._id matching req.params.id
});
to be clear, in the code above, Details is the imported (with require) schema (in your case, the one named schemaMode)
Is "data" your "post"? If so, I think you need a projection.
return details.findOne({'data': {$elemMatch: {'_id':req.params.id}}},{'data.$'}).then((a) => {
return res.render('post', { a.data[0] });
}).catch(err => console.log(err));
'data.$' will project you the whole model, filled only with the desired "data"/"post"

Grab object from MongoDB but limit number of items pulled from array

My API currently has a route for Getting an event from my MongoDB database based on event_id. This works fine. However, I have a 'photos' array within this event object that is growing (currently over 3,000 objects within this array).
I want to pass a limit parameter to limit the number of results pulled from this array, but cannot figure out how. Below is my current node route and mongoDB schema:
route:
// get event by _id
app.get('/api/events/:event_id', function(req, res) {
// use mongoose to get event
Event.findOne({object_id: req.params.event_id}, function(err, event) {
// if there is an error retrieving, send the error. nothing after res.send(err) will execute
if (err)
res.send(err)
if (req.params.limit >= 0) {
// res.jsonp(event) with photos array limited to req.params.limit
}
res.jsonp(event); // return event in JSON format
});
});
schema:
var eventSchema = new Schema({
event: String,
city: String,
state: String,
date: String,
start: String,
end: String,
dateState: String,
radius: String,
team_1: String,
team_2: String,
object_id: String,
longitude: String,
latitude: String,
cover: {
img: String,
username: String
},
photos: []
})
Don't have a constantly growing array field. It's not good for performance because MongoDB (well, if <= 2.6/using mmap) will be moving the document around when it grows outside of the space allocated for it by the storage engine, causing performance problems. You should change your schema to avoid an array like this, but I can't really say more about how you should do it because I don't know much about your use case.
There is a way to limit the number of array elements returned in a find query though, using $slice projection.
> db.test.drop()
> db.test.insert({ "_id" : 0, "x" : [0, 1, 2, 3, 4] })
> db.test.find({ "_id" : 0 }, { "x" : { "$slice" : 2 } })
{ "_id" : 0, "x" : [0, 1] }
Event.findOne({object_id: req.params.event_id})
.limit(10)
.exec(function(e,doc){
...
});
Edit
Or if you have ref on the photo... you can populate the doc array of referenced id with limit option. Hope it helps :) All abount population
.find(...)
.populate({
path: 'photos',
options: { limit: 5 }
})
.exec(...)
Schema
var eventSchema = new Schema({
event: String,
city: String,
state: String,
...
photos: [{ type:String, ref:'pictureSchema' }]
}
var pictureSchema = new Schema({
name : {type:String},
url : {type:String},
...
}
In photos array than you just put id of the pictures doc, when you populate the photos array it will put pictureSceham doc insted of _id.

Categories

Resources