Mongoose Aggregate Return to REST API - Cast to ObjectId failed for value - mongodb

I am trying to set the result of my aggregate call from mongodb to a rest api endpoint. The goal is to get the count of the number of times each manager is in the collection. Below are my dependencies:
"body-parser": "^1.14.2",
"express": "^4.13.4",
"mongoose": "^4.4.2",
"nodemon": "^1.8.1",
Mongoose Schema:
var projectSchema = new Schema({
client: String,
project: String,
series: String,
manager: String,
pieceCount: Number,
dateShipped: Date,
comments: String,
items: [{description: String, barcode: Number, quantity: Number, box:
Number,returned: Boolean, dateReturned: Date}]});
Project = mongoose.model('Project', projectSchema);
Aggregate Call:
var getTotalManagers = function () {
Project.aggregate([
{ $group: {
_id: '$manager',
"total": {$sum:1}}}],
function (err, res) {
if (err) {
console.log(err);
} else {
console.log(JSON.stringify(res));
/* return (JSON.stringify(res)); (what is used when not writing to
console */
}
});
};
getTotalManagers();
This returns the desired results to the console:
[{"_id":"Fname Lname","total":1},{"_id":"Fname Lname","total":1},
{"_id":"Fname Lname","total":4},{"_id":"Fname Lname","total":2},
{"_id":"Fname Lname","total":2}]
Rest API Call:
router.get('/totals',getTotalManagers);
I get this error message when trying to access the api call:
{
"message": "Cast to ObjectId failed for value \"totals\" at path \"_id\"",
"name": "CastError",
"kind": "ObjectId",
"value": "totals",
"path": "_id"
}
What is the proper way to set this to a rest api endpoint? I feel like that is the issue since the aggregate call is working to the console. Any help would be appreciated. Thanks.

Related

Graphql apollo playground - how to add array of strings

tldr: How do I write a mutation in GraphQL playground to add an array of strings when creating a new record in the database
I'm using a MongoDB database for an application. I always have trouble finding documentation for how to write queries and mutations in GraphQL apollo playground. In this example, let's take an example of an athlete. An athlete can win many awards. The awards are just an array of strings. I will use a simple model as an example...
const playerSchema = new Schema({
playerName: {
type: String,
required: true,
},
awards: [{
type: String,
}]
})
const Player = model('Player', playerSchema)
module.exports = Player;
Here is my typeDef for this model with Queries and Mutations
const typeDefs = gql`
type Player{
playerName: String!
awards: [String]
}
type Query {
players: [Player!]
}
type typeDefs {
addPlayer:(playerName: String!, awards:[String]
}
}`;
module.exports = typeDefs;
Here is my resolvers for this model
const resolvers = {
Query: {
players: async () => {
return await Player.find(populate('player');
}
Mutation: {
addPlayer: async( parent, {playerName, awards}) => {
return await Player.create({playerName, awards})
}
}
module.exports = resolvers;
Now, I start the server and go to GraphQL playground in the browser. I cannot add an array of strings for the awards. How do I write this query in GraphQL playground? Here is an example of my best attempt:
mutation addPlayer($playerName: String!, $awards:[String]){
addPlayer(playerName:$playerName, awards:$awards){
playerName
awards
}
}
and finally my query variables for this mutation
{
"playerName": "Michael Jordan",
"awards": ["Most Valuable Player", "Rookie of the Year", "Scoring Champion"]
}
If I run a query in GraphQL to see what players exist in the database:
query players{
players{
playerName
awards
}
}
This is the results. Why is the 'awards' array empty??
{
"data": {
"players": [
{
"playerName": "Michael Jordan",
"awards": [], //EMPTY ARRAY HERE, WHY?
}
]
}
}

Documents inserted without schema not being found with schema

I have two new collections in MongoDB of data that I pulled from an old Firestore database that I'm moving to mongo. Since the total number between these two collections is roughly 20,000, I opted to paste the raw JSON into the insert document section in mongo, which worked like a charm and I didn't have to write a new insert route to do the same.
I then created a schema in Mongoose that matched the inserted documents, and tried to use the schema to pull back some data, and its always returning nothing.
An example of a ticket inserted via JSON:
{
"title": "How to add and manage users for your company in QuickBooks Online",
"priority": "1",
"type": "Video",
"course": "G205",
"transcriptId": "07dom27Zz98jakvB1oh5",
"status": "In Review",
"tags": "",
"url": "",
"revisionNumber": 0,
"directoryId": 19,
"checkedOut": false
},
And my schema I made to match. The collection name in mongo is also called oldTickets, the plural of my schema name here:
const mongoose = require('mongoose');
var Schema = mongoose.Schema
const schema = new Schema({
course: { type: String },
title: { type: String },
priority: { type: String },
type: { type: String },
course: { type: String },
transcriptId: { type: String },
status: { type: String },
tags: { type: String },
url: { type: String },
revisionNumber: { type: Number },
directoryId: { type: Number },
checkedOut: { type: Boolean },
});
module.exports = mongoose.model('oldTicket', schema);
And finally my model import and fetch call:
const OldTicket = require('./models/model_old_ticket');
/***************************************************************************
* Get Old Tickets - Returns all old tickets, 10 at a time
****************************************************************************/
app.get('/getOldTickets/:offset', (req, res) => {
checkConnection();
OldTicket.find().skip(parseInt(req.params.offset)).limit(10).exec((err, data) => {
if (err){ res.status(500).send({err: err}); }
//If we got data, count the tickets & return the tickets & count
if (data) {
OldTicket.find().countDocuments().then(count => {
return res.status(200).send({
tickets: data,
count: count
})
})
}
});
});
Why isn't this finding anything? Both the count and the tickets are 0. I've run into this issue before when manually creating a collection without a schema, and in those instances I would simply delete the collection, write a route to create a document, and then things would work fine. But with the large data size of these two collections, I'd rather not do that since everything should be working as is.
Edit: Example of document in Mongo
And the name of the collection I'm currently viewing:
And I just now realized that for some reason there are now two collection names, oldTickets, which has data, and oldtickets, which is empty. I'm assuming my query is searching through the empty one? How can I get it to go to the one that actually has data?
can you attach the screenshot of your data with the collection? might be it's different.in mongoose, every collection name is complete with 's'. please verify your collection is created manually by you then it has to same as mongoose schema and also completed with 's'.
example:
const mongoose = require("mongoose");
const schema = new mongoose.Schema(
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
index: true
},
filmId: {
type: mongoose.Schema.Types.ObjectId,
index: true
},
filmType: {
type: String,
index: true
},
birthday: {
type: Date
},
age: {
type: Number
},
terms: {
type: Boolean
}
},
{
versionKey: false,
timestamps: true,
}
);
schema.index({ filmId: 1, user: 1 })
module.exports = mongoose.model("UserAgeVerification", schema);
see my database

Why I'm I getting an error saving date using graphql > hasura > postgres

I'm using react, apollo, graphql, hasura, postgres as my stack to interact with the database. I think my issue is something small, so I'll just focus on the part that's not working rather than posting the whole code.
Thanks.
Error: GraphQL error: unexpected variables in variableValues: birthday
at new ApolloError (bundle.esm.js:63)
at Object.next (bundle.esm.js:1004)
at notifySubscription (Observable.js:135)
at onNotify (Observable.js:179)
at SubscriptionObserver.next (Observable.js:235)
at bundle.esm.js:866
at Set.forEach (<anonymous>)
at Object.next (bundle.esm.js:866)
at notifySubscription (Observable.js:135)
at onNotify (Observable.js:179)
at SubscriptionObserver.next (Observable.js:235)
at bundle.esm.js:76
variables{ id: 2324324, name: "Fred", birthday: "1991-01-11" }
If i remove birthday the query works.
Here is the function
const onUpdateUser = (options) => {
updateUser({
variables: Object.assign({ id: userId }, options),
optimisticResponse: {
__typename: "mutation_root",
update_users: {
__typename: "users_mutation_response",
affected_rows: 1,
returning: [
{
__typename: "users",
id: userId,
...options,
},
],
},
},
});
};
input {birthday: '1991-01-11'}
So without looking at your graphql query, I think you may be thinking of it a little bit off.
You can't dynamically add non-existent variables to a graphql query. The error is telling you that you are trying to add a variable that doesn't exist in your query
i.e. this with NOT work because you haven't defined birthday.
mutation updateUser(
$userId: Int!
$birthday (UNDEFINED)
) {
rest of query...
}
If you need to add a dynamic amount of variables, you could do something like this.
React Code
const onUpdateUser = (options) => {
updateUser({
variables: {
userId,
userVariables: options
},
optimisticResponse: {
__typename: "mutation_root",
update_users: {
__typename: "users_mutation_response",
affected_rows: 1,
returning: [
{
__typename: "users",
id: userId,
...options,
},
],
},
},
});
};
GraphQL mutation
mutation updateUser(
$userId: Int!
$userVariables: user_set_input!
) {
update_user(
where: { id: { _eq: $userId} }
_set: $userVariables
) {
affected_rows
}
}
https://hasura.io/docs/1.0/graphql/manual/mutations/update.html

Distinct Query with Cloudant Connector using Loopback in API Connect/StrongLoop

I am trying to get distinct values for a query using Loopback with a Cloudant Connector, but I haven't found anything about this in the documentation.
e.g. I need a query to turn this:
[
{
rating: "★★★★★"
},
{
rating: "★★★★★"
},
{
rating: "★★★★★"
},
{
rating: "★★★★★"
},
{
rating: "★★★☆☆"
},
{
rating: "★★★☆☆"
}
]
into this:
[
{
rating: "★★★★★"
},
{
rating: "★★★☆☆"
}
]
I'm using the REST API to query my Products model (above is a filtered view of just the rating field). If there is some sort of filter that I can use without modifying the server that I somehow just missed in the documentation, that would be the best choice.
Is there any way I can add a distinct field like:
/Products?filter[fields][rating]=true?distinct=true
or how can I go about solving this?
Also, I've seen another answer talking about adding a remote method to solve this (something like this for mySQL):
Locations.regions = function (cb) {
var ds = Locations.app.datasources.myDS;
var sql = "SELECT DISTINCT region FROM Locations ORDER BY region"; // here you write your sql query.
ds.connector.execute(sql, [], function (err, regions) {
if (err) {
cb(err, null);
} else {
cb(null, regions);
}
});
};
Locations.remoteMethod(
'regions', {
http: {
path: '/regions',
verb: 'get'
},
returns: {
root: true,
type: 'object'
}
}
);
If this would work, how would I implement it with the Cloudant NoSQL DB connector?
Thanks!
If your documents looked like this:
{
"name": "Star Wars",
"year": 1978,
"rating": "*****"
}
You can create a MapReduce view, which emits doc.rating as the key and uses the build-in _count reducer:
function(doc) {
emit(doc.rating,null);
}
When you query this view with group=true, distinct values of rating will be presented with counts of their occurrence in the data set.

Expressjs collection.update $push result with TypeError: Cannot call method 'update' of undefined

I try to create valid geojson FeatureCollection and some problems occurred during updating document in collection.
My Model
var mongoose = require('mongoose');
Schema = mongoose.Schema;
var DataSchema = new Schema({
type: {type:String, default:"Feature"},
properties:{
title: { type: String, required: true },
description: { type: String, required: true},
date: {type:Date, default:Date.now}},
geometry:{
type:{type:String, default:"Point"},
coordinates: {type: [Number]}}
});
var MetadataSchema = new mongoose.Schema({
type : {type: String, default: "FeatureCollection"},
features: [DataSchema]
});
var rescueModel = mongoose.model('rescueModel', MetadataSchema);
Router
router.post('/mountain_rescue', function(req, res){
db.collection('rescuemodels', function(err, collection){
collection.update({
"type": "FeatureCollection"
},
{
$push: {
"features": {
properties: {
title: req.body.title,
description: req.body.description
},
geometry: {
coordinates: req.body.coordinates.split(',')
}
}
}
});
res.redirect('/mountain_rescue');
});
});
module.exports=rescueModel;
So If everything is okay but why is it that after executing post route I get
TypeError: Cannot call method 'update' of undefined
I also checked the command in mongo shell and it works
db.rescuemodels.update(
{
"type":"FeatureCollection"
},
{
$push:{
"features": {
"properties":{"title":"WOW"}
}
}
}
)
The problem is that collection is not defined before running the update. Also, you might want to do the redirect in the callback to the update function, but that will depend on the behaviour you are looking for. Your code would then look something like this:
var collection = db.collection('rescuemodels');
collection.update({
"type": "FeatureCollection"
},
{
"$push": {
"features": {
"properties": {
"title": req.body.title,
"description": req.body.description
},
"geometry": {
"coordinates": req.body.coordinates.split(',')
}
}
}
}, function(err, result) {
if (err) throw err;
res.redirect('/mountain_rescue');
});