Make a limit in a sub array of a MongoDB document - node.js

I have a MongoDB collection that allows to store videos rankings, here is the schema:
var ChallengeVideoRankingSchema = new Schema({
_challenge: {
type: ObjectId,
ref: 'Challenge',
},
since: {
type: String,
enum: ['all', 'day', 'week', 'month']
},
type: {
type: String,
enum: ['won_duels', 'diamonds']
},
total: {
type: Number
},
challengeVideos: [
{
rank: {
type: Number
},
_challengeVideo: {
type: ObjectId,
ref: 'ChallengeVideo'
}
}
],
creation_date: {
type: Date,
default: Date.now
},
});
I would like to make a request with mongoose which allows me to retrieve some of the ChallengeVideo objects in one of the rankings to make a pagination. I would like for example to have in the field "challengeVideos", 20 objects representing the ranks 1-20, 21-40, 41-60, ... according to a given parameter.
Thank you in advance,
Bastien

Get last elements with slice
db.posts.find( {}, { comments: { $slice: -3 } } )
link https://www.mongodb.com/docs/manual/reference/operator/projection/slice/#return-an-array-with-its-last-3-elements

Related

get locations by grouping with mongodb

good work.
I have a mongoose schema similar to the following
const mongoose = require('mongoose')
var stations = new mongoose.Schema({
//başlık
title: {
type: String
},
//tam adresi
address: {
default:"-",
type: String
},
//ücretlendirme bilgisi
tariff_information: {
default:"-",
type: String
},
//soketler
sockets: {
type: Array,
default:[]
},
//şarj türü (SADECE AC VEYA DC)
type: {
type: String
},
//istasyon sahibi
station_owner: {
type: String
},
//istayon benzersiz kodu
station_code: {
default:"-",
type: String
},
//gps koordinatı
loc: {
"type": {
type: String,
enum: ['Point'],
default: 'Point',
},
"coordinates": {
type: [Number],
default: [0, 0], //[LONG , LAT]
required:true
},
},
}, { timestamps:true, skipVersioning: { dontVersionMe: true } })
stations.index({loc:"2dsphere"})
module.exports = mongoose.model("stations", stations, "stations");
I want to get the data by grouping from here, for example, if there are 1000 locations in 10 km2 area, I want it to return only 1 of them to me.
The reason why I want this is that I have close to 10 million documents in my collection and I'm trying to show it on a map, but it doesn't work at all. Let me reply with a minimum distance of 10km between the locations I want.
I tried using $geoHaystack but it is deprecated. I tried with $geoNear and still couldn't get the result I wanted.

How Can i create min and max range filter in mongodb

how can i create mongodb query min and max price , based on min price and max price product form specific category ?
const productSchema: Schema = new Schema({
title: { type: String, required: true },
price: { type: Number, required: true },
stock: { type: Number, required: true },
slug: { type: String },
sale_price: { type: Number, default: 0 },
thumbnail: { type: Schema.Types.ObjectId, ref: "FileManager" },
description: { type: String, required: true },
category: { type: Schema.Types.ObjectId, ref: "Category" },
attributes: { type: [Object], required: true },
created_at: { type: Date, default: Date.now },
updated_at: { type: Date, default: Date.now },
status: { type: ProductStatus, default: ProductStatus.INIT },
});
Your question seems a bit vague. A bit more info is required, but if you want to do this, I suggest using Mongoose aggregations. This gathers all the documents, sorts them, then groups them based on what you want them to be grouped by.
It looks something like this:
// Model = Product
const minMax = await Product.aggregate([
{
$match: {// filter the products}
},
{
$group: {
// Get min price
// Get max price
}
}
]);
Aggregate is a pretty big topic to explain, but it can be very powerful for gathering statistics like max/min values.
Obviously, the comments are there to guide you and are not the actual code in the aggregate. I would highly recommend looking at that link, and if your feeling lazy, just look at a quick youtube video explaining mongoose aggregate.
you can also try.
db.collections.find({ price: { $gte: 50, $lte: 10000 } } );
here 50 means minimum price & 10000 means maximum price.

Error in getting referenced objects in admin-bro Nodejs (There are no resources with given id)

So the error I am getting is There are no resources with given id: "workshop.timelines"\nThis is the list of all registered resources you can use.
This is the resource I am trying to visualize in adminbro
const LearnerSchema = new mongoose.Schema(
{
workshops: [
{
workshop: {
workshop_id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'workshop',
},
code: {
type: String,
},
timeline: {
type: mongoose.Schema.Types.ObjectId,
ref: 'workshop.timelines',
},
},
],
{ timestamps: true }
);
This is the workshop model:
const WorkshopSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
},
description: {
type: String,
},
timelines: [
{
group: {
type: Number,
},
city: {
type: mongoose.Schema.Types.ObjectId,
ref: 'city',
},
description: {
type: String,
},
venue: {
type: mongoose.Schema.Types.ObjectId,
ref: 'venue',
},
month: {
type: String,
},
start: {
type: Date,
},
end: {
type: Date,
},
registration_start: {
type: Date,
},
registration_end: {
type: Date,
},
registrations: {
type: Number,
default: 0,
},
registrations_cancelled: {
type: Number,
default: 0,
},
d_reg: {
type: Number,
default: 0,
},
classLink: {
type: String,
default: '',
},
status: {
type: String,
default: 'E',
},
resources: {
_id: false,
videoSessions: { type: Boolean, default: false },
},
},
],
status: {
type: String,
enum: ['NEW', 'F', 'DISABLED'], //f = FEATURED
default: 'NEW',
},
},
{ timestamps: true }
);
WorkshopSchema.index({ name: 'text', description: 'text' });
module.exports = Workshop = mongoose.model('workshop', WorkshopSchema);
Now, I have added both of these resources among others in my adminbro options, but when adminbro tries to fetch some records from the Collection, it fails with the error:
There are no resources with given id: "workshop.timelines"\nThis is the list of all registered resources you can use.
One more thing that might be affecting this issue is that in MongoDB the value of timelines in the workshop object is a mix of ObjectId and string, however I have tried converting all the object values to ObjectId but it still shows the same error.
Would really appreciate any help here.
had the same issue.
Basically, any ref model that appears in the models that are included in the resources array has to be included as well.
In your case, I will suggest to have a look at the ResourceOptions (https://adminbro.com/ResourceOptions.html) to see if you can included the nested property
comment out you're every (type: mongoose.Schema.Types.ObjectId,) to like this ↓↓ or you can delete it as well.
// type: mongoose.Schema.Types.ObjectId,
and it will work fine.
This is not working because by default, Mongoose adds an _id property to your schemas and you are explicitly defining it so need to explicitly insert it while creating but in AdminBro Dashboard you do not have that kind of option to add _id while creating any new Object. So, for that reason comment every _id generating field.

Getting CoreMongooseArray instead of normal array

I have this schema:
var orderSchema = new mongoose.Schema({
history: [{
"type": {
type: String,
enum: [
'ORDER_HISTORY_DRIVER_DETAILS',
'ORDER_HISTORY_LOADING',
'ORDER_HISTORY_LOCATION',
'ORDER_HISTORY_UNLOADING'
],
required: true
},
date: {
type: Date
},
state: {
type: String,
enum: [
'ORDER_HISTORY_STEP_STATE_COMPLETED',
'ORDER_HISTORY_STEP_STATE_CURRENT',
'ORDER_HISTORY_STEP_STATE_FUTURE',
],
default: 'ORDER_HISTORY_STEP_STATE_FUTURE',
required: true
}
}]
})
At one point, I need to remove all subdocuments that have a type of "ORDER_HISTORY_LOCATION", so I'm running this:
let result = await Order.findOneAndUpdate(
{orderId: req.params.orderId},
{
$pull: {
history: {type: "ORDER_HISTORY_LOCATION"}
}
}, {new: true}
);
When i log "result.history" i get this:
CoreMongooseArray [
{ state: 'ORDER_HISTORY_STEP_STATE_CURRENT',
_id: 5caf8a41641e6717d835483d,
type: 'ORDER_HISTORY_DRIVER_DETAILS' },
{ state: 'ORDER_HISTORY_STEP_STATE_FUTURE',
_id: 5caf8a41641e6717d835483c,
type: 'ORDER_HISTORY_LOADING',
date: 2019-05-08T09:00:00.000Z },
{ state: 'ORDER_HISTORY_STEP_STATE_FUTURE',
_id: 5caf8a41641e6717d835483b,
type: 'ORDER_HISTORY_LOADING',
date: 2019-05-09T09:00:00.000Z },
{ state: 'ORDER_HISTORY_STEP_STATE_FUTURE',
_id: 5caf8a41641e6717d8354837,
type: 'ORDER_HISTORY_UNLOADING',
date: 2019-05-13T09:00:00.000Z } ]
What is this "CoreMongooseArray"? I can't do anything with it. I also can't find any documentation on it.
CoreMongooseArray seems to be inheriting the Array type and has almost the same behavior.
Source code (at the time of writting) : https://github.com/Automattic/mongoose/blob/3e523631daa48a910b5335c747b3e5d080966e6d/lib/types/core_array.js
In case you want to convert it to a simple array, just do this :
const history = Array.from(...result.history)
Beware, if this array contains objects, each object will have undesirable additional Mongoose properties, as they are Mongoose schemas documents. You will need to convert them into plain JavaScript objects :
const history = Array.from(...result.history).map(v => v.toJSON())
Hope it helps.
This worked for me!
const history = Array.from([...result.history])

Populate + Aggregate in Mongoose [duplicate]

This question already has answers here:
Mongoose - How to group by and populate?
(3 answers)
Closed 6 years ago.
I have two Mongoose models: one for transactions and the other one for the tags associated with them. In order to implement some reports, I need aggregate code like this:
Transaction.aggregate([
{ $unwind: '$tags' },
{
$group: {
_id: '$tags',
amount: {
$sum: '$amount'
}
}
}
])
Question
This produces output containing _id and amount. Now, I'd like to populate the other fields (e.g. name) from the model, keeping the calculated amount column. Can I do that within a simple populate?
Edit
The schemas for the models I'm describing:
var TransactionSchema = new Schema({
description: {
type: String,
trim: true
},
amount: {
type: Number,
required: 'Forneça um valor',
},
date: {
type: Date,
required: 'Forneça uma data',
default: Date.now
},
fromOfx: {
type: Boolean,
default: false
},
created: {
type: Date,
default: Date.now
},
correlated: {
type: Boolean,
default: false
},
tags: [{
type: Schema.Types.ObjectId,
ref: 'TransactionTag'
}],
correlates: [{
type: Schema.Types.ObjectId,
ref: 'Transaction'
}],
user: {
type: Schema.Types.ObjectId,
ref: 'User'
}
});
var TransactionTagSchema = new Schema({
name: {
type: String,
required: 'Forneça um nome',
trim: true
},
description: {
type: String,
trim: true
},
amount: {
type: Number
}
});
You can populate an aggregation after you fetched the data from the MongoDB. This will look something like this:
// Your aggregate query from your question
Transaction.aggregate([{
$unwind: '$tags'
}, {
$group: {
_id: '$tags',
amount: {
$sum: '$amount'
}
}
}])
.exec(function(err, transactions) {
// Don't forget your error handling
// The callback with your transactions
// Assuming you are having a Tag model
Tag.populate(transactions, {path: '_id'}, function(err, populatedTransactions) {
// Your populated translactions are inside populatedTransactions
});
});

Resources