I am getting error in graphql while making query for specific id - mongodb

schema:
const UserType = new GraphQLObjectType({
name: 'User',
fields: () => ({
id : { type: GraphQLID },
name : { type: GraphQLString },
email : { type: GraphQLString },
})
})
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
user: {
type: UserType,
args: {
id: { type: GraphQLID }
},
resolve(parent, args){
return User.findById(args.id);
}
}
}
})
module.exports = new GraphQLSchema({
query: RootQuery
});
Here i am fetching data by id from mongodb.
I am using mongoose for mongodb client.
I have setup server with express and graphql.
and i am making below query to get result by specifi id
{
user(id: 2){
name
}
}
But, i am getting below error while making query.
{
"errors": [
{
"message": "Cast to ObjectId failed for value \"2\" at path \"_id\" for model \"User\"",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"user"
]
}
],
"data": {
"user": null
}
}
my id in database is just a integer value like below
{
"_id" : ObjectId("5d49c6dc54f1cec013ee6b49"),
"id" : 10,
"name" : "Clementina DuBuque",
"email" : "Rey.Padberg#karina.biz",
}
Please have a look.

type: UserType this should be type: new GraphQLList(UserType),

Related

How to update with mongoose

I have this record
{
"_id" : ObjectId("5dfdff479ad032cbbc673507"),
"selection" : [
{
"highlights" : "test",
"comment" : "CHANGE THIS",
"el" : "body:nth-child(2)>div:nth-child(2)#root>div.App>p:nth-child(1)"
},
{
"highlights" : "Barrett’s lyrical prose opens with a clever and tender solution",
"comment" : "",
"el" : "body:nth-child(2)>div:nth-child(2)#root>div.App>p:nth-child(2)"
}
],
"category" : [],
"status" : "",
"url" : "http://localhost:3000/theone",
"title" : "React App test",
"__v" : 4
}
And I want to update the comment. I have tried to use update and findOneAndUpdate and nothing is working. Here is my attempt
WebHighlight.findOneAndUpdate(
{
_id: req.params.highlight,
"selection.highlights": "test"
},
{ "selection.$.comment": "yourValue" }
);
That req.params.highlight is the id (I even hardcoded it)
I also tried this
WebHighlight.findById(req.params.highlight, (err, book) => {
var test = [...book.selection];
test[0].comment = "somethibf"
book.save();
res.json(book);
});
And nothing is working.
This is the model
const webhighlightsModel = new Schema({
selection: { type: Array, default: "" },
category: { type: Array, default: [] },
title: { type: String },
url: { type: String },
status: { type: String, default: "" }
});
Actually your code seems to work, but findOneAndUpdate returns the old document if you don't give {new: true} option.
I think for this reason, you think the update wasn't successfull, but if you check your collection, you will see the update.
WebHighlight.findOneAndUpdate(
{
_id: req.params.highlight,
"selection.highlights": "test"
},
{ "selection.$.comment": "yourValue" },
{ new: true }
)
.then(doc => res.send(doc))
.catch(err => res.status(500).send(err));
Also I think it would be better if selection had a sub schema like this:
const mongoose = require("mongoose");
const schema = new mongoose.Schema({
selection: [
new mongoose.Schema({
highlights: String,
comment: String,
el: String
})
],
category: { type: Array, default: [] },
title: { type: String },
url: { type: String },
status: { type: String, default: "" }
});
module.exports = mongoose.model("WebHighlight", schema);
So with this every selection would an _id field, and it would be better to update with this _id.
You should use the $set operator to update existing values:
WebHighlight.findOneAndUpdate(
{
_id: req.params.highlight,
"selection.highlights": "test"
},
{ '$set': { "selection.$.comment": "yourValue" } }
);

graphql mongoose must be Output Type but got: undefined

schema:
const graphql = require("graphql");
const User = require("../models/user");
const {
GraphQLObjectType,
GraphQLString,
GraphQLInt,
GraphQLSchema,
GraphQLID,
GraphQLList
} = graphql;
const CompanyType = new GraphQLObjectType({
name:'Company',
fields: () => ({
name: { type: GraphQLString },
catchPhrase: { type: GraphQLString },
bs: { type: GraphQLString },
})
})
const UserType = new GraphQLObjectType({
name: 'User',
fields: () => ({
id : { type: GraphQLID },
name : { type: GraphQLString },
username : { type: GraphQLString },
email : { type: GraphQLString },
address : { type: GraphQLString },
phone : { type: GraphQLInt },
website : { type: GraphQLString },
company : new GraphQLList(CompanyType)
})
})
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
user: {
type: UserType,
args: {
id: { type: GraphQLID }
},
resolve(parent, args){
return User.findById(args.id);
}
},
users: {
type: new GraphQLList(UserType),
resolve(parent, args){
return User.find({});
}
}
}
})
module.exports = new GraphQLSchema({
query: RootQuery
});
model:
const mongoose = require('mongoose');
const Scheme = mongoose.Schema;
const userSchema = new Scheme({
id : Number,
name : String,
username : String,
email : String,
address : Object,
phone : Number,
website : String,
company : Object
})
module.exports = mongoose.model('User', userSchema)
Here i am trying to fetch data from mongodb database.
I have setup my server with expressjs with graphql and using mongoose for mongodb client.
But while making quesry in graphiql i am getting below error:
{
"errors": [
{
"message": "The type of User.company must be Output Type but got: undefined."
}
]
}
My result is with nested json so i am using GraphQLList .
Please have a look where i am doing wrong
company : {type: CompanyType}
and schema should be
const userSchema = new Scheme({
id : Number,
name : String,
username : String,
email : String,
address : Object,
phone : Number,
website : String,
company : {
name: String,
catchPhrase: String,
bs: String
}
})

Mongoose query on subdocument returns array of other subdocument using projection

Update: I am looking for an answer that works within mongodb projection: https://docs.mongodb.com/manual/reference/method/db.collection.findOne/#definition
I am trying to filter a query on a subdocument using projection so that it only returns a specific array. But when filtering the result also includes an array of another subdocument. When I don't filter it only returns the found document.
I tried different filtering options including and excluding positional elements, but can't get the desired return.
Mongoose schema
const stationSchema = new mongoose.Schema({
mac: String,
stationName: String,
syncReadings: Boolean,
temperature: Array,
humidity: Array,
measures: [{
date: Date,
temperature: Number,
humidity: Number
}],
lastUpdated: Date
});
// Define user schema
var userSchema = mongoose.Schema({
local : {
email : String,
password : String
},
facebook : {
id : String,
token : String,
name : String,
email : String
},
twitter : {
id : String,
token : String,
displayName : String,
username : String
},
google : {
id : String,
token : String,
email : String,
name : String
},
apiKey: String,
stations : [stationSchema]
},
{
usePushEach: true
}
);
Api handler
app.get('/api/stations/:stationName/measures', function(req, res, next) {
var user = {
apiKey: req.user.apiKey
}
const query = {
apiKey: user.apiKey,
stations.stationName': req.params.stationName
}
const options = {
'stations.measures': 1
}
User.findOne(query, options)
.exec()
.then(stations => {
res.status(200).send(stations)
})
.catch(err => {
console.log(err);
res.status(400).send(err);
})
});
There are two stations under one user:
[
{
"_id": "5c39c99356bbf002fb092ce9",
"stations": [
{
"stationName": "livingroom",
"mac": "5C:CF:7F:77:12:FB",
"_id": "5c39c9ab56bbf002fb092cea",
"lastUpdated": "2019-01-12T11:07:01.802Z",
"syncReadings": false,
"measures": [],
"humidity": [],
"temperature": [
{
"date": "2019-01-12T11:07:01.802Z",
"temperature": "20"
}
]
},
{
"stationName": "office",
"mac": "5C:CF:7F:77:12:FC",
"_id": "5c39cacdce4ac903123f0150",
"measures": [],
"humidity": [],
"temperature": []
}
]
}
]
API call
http://localhost:8080/api/stations/livingroom/measures
Result
{
"_id": "5c39c99356bbf002fb092ce9",
"stations": [
{
"measures": []
},
{
"measures": []
}
]
}
Projection options tried
const options = {
'stations.measures': 1
}
const options = {
'stations.$.measures': 1
}
const options = {
'stations.$': 1,
'stations.$.measures': 1
}
const options = {
'stations.$': 1,
'stations.measures': 1
}
What am I doing wrong?
try using these querying params only and after that you will get a user with a requested station..
var user = {
apiKey: req.user.apiKey
}
const query = {
apiKey: user.apiKey,
'stations.stationName': req.params.stationName
}
then do this
User.findOne(query, options)
.exec()
.then(stations => {
for(let station of stations){
if(station.measures[1]){ // here it is the index
res.status(200).send(stations);
}
}
})
.catch(err => {
console.log(err);
res.status(400).send(err);
})
actually in mongoose you cannot query sub-sub documents to you will have to you this approach.. You can only query sub docs only like you have done

Mongoose find() returning array empty

I have the following product model:
'use strict';
let mongoose = require('mongoose');
let Schema = mongoose.Schema;
// create a schema
let produtoSchema = new Schema(
{
descricao: { type: String, required: true },
gateways: [ { type : mongoose.Types.ObjectId, ref: 'Gateway' } ]
}
);
mongoose.model('Produto', produtoSchema);
The the following collection:
rs0:PRIMARY> db.produtos.find().pretty()
{
"_id" : ObjectId("55fef1a3d7c6912033f2da72"),
"descricao" : "Product description",
"gateways" : [
ObjectId("55fee8a97cb7db7740acb322")
]
}
rs0:PRIMARY>
So, I'm trying to use Mongoose to fetch a specific product, but 'gateway' array is empty :
let Produto = mongoose.model('Produto');
Produto.find(
{
_id: mongoose.Types.ObjectId("55fef1a3d7c6912033f2da72")
}, function(err, result)
{
if (err) console.log(err);
console.log(result);
});
And the result is :
[ { _id: 55fef1a3d7c6912033f2da72,
descricao: 'Product description',
gateways: [] } ]
A also tried, but with the same result:
Produto
.find( { _id: mongoose.Types.ObjectId("55fef1a3d7c6912033f2da72") })
.populate('gateways')
.exec(function(err, result)
{
if (err) console.log(err);
console.log(result);
});
Any idea of what I'm doing wrong ?
Thanks.
I've found the problem.
I've changed:
gateways: [ { type : mongoose.Types.ObjectId, ref: 'Gateway' } ]
by
gateways: [ { type : mongoose.Schema.ObjectId, ref: 'Gateway' } ]
What's the difference between them ?

Correct way to return from mongo to datatable

I'm using mongoose and returning documents from a collection to be displayed using datatables. I'm having some issues though. The client-side code is
var table = $('#dataTables-example').DataTable( {
"bProcessing" : true,
"bServerSide" : true,
"ajax" : {
"url" : "/mongo/get/datatable",
"dataSrc": ""
},
"columnDefs": [
{
"data": null,
"defaultContent": "<button id='removeProduct'>Remove</button>",
"targets": -1
}
],
"aoColumns" : [
{ "mData" : "name" },
{ "mData" : "price" },
{ "mData" : "category" },
{ "mData" : "description" },
{ "mData" : "image" },
{ "mData" : "promoted" },
{ "mData" : null}
]
});
Then this handled on the server-side using the following
db.once('open', function callback ()
{
debug('Connection has successfully opened');
productSchema = mongoose.Schema({
name: String,
price: String,
category: String,
description: String,
image: String,
promoted: Boolean
});
Product = mongoose.model('Product', productSchema, 'products');
});
exports.getDataForDataTable = function (request, response) {
Product.dataTable(request.query, function (err, data) {
debug(data);
response.send(data);
});
};
If I use the above code the datatable fails to display the documents, claiming no matching records found BUT it does correctly display the number of docs Showing 1 to 2 of 2 entries. If I change the server side code to response with data.data instead of data, the documents are correctly populated in the table BUT the number of records is no longer found, instead saying Showing 0 to 0 of 0 entries (filtered from NaN total entries)
exports.getDataForDataTable = function (request, response) {
Product.dataTable(request.query, function (err, data) {
debug(data);
response.send(data.data);
});
The actual data being returned when querying mongo is
{ draw: '1', recordsTotal: 2, recordsFiltered: 2, data: [ { _id: 5515274643e0bf403be58fd1, name: 'camera', price: '2500', category: 'electronics', description: 'lovely', image: 'some image', promoted: true }, { _id: 551541c2e710d65547c6db15, name: 'computer', price: '10000', category: 'electronics', description: 'nice', image: 'iamge', promoted: true } ] }
The third parameter in mongoose.model sets the collection name which is pluralized and lowercased automatically so it has no effect in this case.
Assuming your Product variable has been declared early on and global, try this:
products = mongoose.model('products', productSchema);
Product = require('mongoose').model('products');
Did you try to remove the dataSrc field in the DataTable configuration:
"ajax" : {
"url" : "/mongo/get/datatable",
},