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

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

Related

use where query depends on query on prisma

const fictions = await client.fiction.findMany({
where: {
AND: [
{ genre: genres as string },
{ nationality: nationalities as string },
{
keywords: {
some: {
keyword: {
name: keywords?.toString().split(",").join(" | "),
},
},
},
},
],
},
include: { ~~~
},
orderBy: {
userFictionStat: {
total: "asc",
},
},
});
Hi, I'm new to prisma so stuck in createing api pages.
I want to filter my 'fictions' with multiple criteria
('genre' or 'nationality' or 'keywords').
The problem is that when 'genre' or 'nationality' or 'keywords' are 'undefined'(button unclicked), the result becomes 0.(because of the 'AND').
I can't find out how can I filter my fictions with given criteria(with clicked buttons, even if some buttons are unclicked).
Also, I'd like to know how can I sort my fictions using my queries.
(lik if i get query {sorting : totalpoint} I can sory by totalPoint, and if i get {sorting : title} then I can sort by title name.
If anyone could help, I would be very thank you.
If genres can be undefined or false-y (including '' or "") then you can do typeof genres === "string" ? genres : undefined as part of your filter. Same for nationalities. That way you know you're passing a string which has meaningful content OR you are ignoring the filter.

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?
}
]
}
}

Prisma splice Item from Array

I have been pushing updates to an array and was wondering if there is a built-in method to remove an entry from the array as well. Basically reversing the push command. I suspect that I have to query all documents and remove the item myself. But maybe there is some functionality I was unable to find inside the documentation.
Push:
const addTag = await prisma.post.update({
where: {
id: 9,
},
data: {
tags: {
push: 'computing',
},
},
})
Remove Expectation:
const removeTag = await prisma.post.update({
where: {
id: 9,
},
data: {
tags: {
splice: 'computing',
},
},
})
As of writing, there's no method to splice/remove items from a scalar list using Prisma. You would have to fetch the scalar list from your database, modify it manually in your application code and overwrite the record in your database with an update operation.
There is a feature request for this, please feel free to follow/comment with your use-case to help us track demand for this feature.
const { dogs } = await prisma.user.findOne({
where: {
id: userId
},
select: {
dogs: true
},
});
await prisma.user.update({
where: {
id: userId
},
data: {
dogs: {
set: dogs.filter((id) => id !== 'corgi'),
},
},
});

Mongo DB - How to get only the inserted Object in an array when calling collection.watch()

I am having a little problem with my code.
I have a collection called user_relations and there I save friends that a specific user has.
One document example:
So my question is: How can I only get the Object item that has been added to arrayOfFriends without getting all of the other values inside that array and outside. For example:
If I insert {"userId" : "2", "lastMessage" : "Hello"} into arrayOfFriends, I want that my response looks like this: {"userId" : "2", "lastMessage" : "Hello"} and not like this {"_id" : ObjectId("id..."), "arrayOfFriends" : {...}}.
The code that I am currently using:
var stream = db.collection('user_relations').watch(<Map<String, Object>>[
{
'$match': {
'$and': [
{'operationType': 'insert'},
{'fullDocument.userId': '6fcfd7b3847dd9999430f1ad'}
]
}
}
]);
stream.listen((changeEvent) {
Map fullDocument = changeEvent.fullDocument;
print('fullDocument: $fullDocument');
// Insert your logic here
});
The code is written in flutter, but I think it is pretty similar to Node.js and Python and can be read easily.
Thank You!
I believe the OP was asking about how to create this using Flutter. Nonetheless here is a node example not using mongoose, but only using the raw driver...
npm init -y
npm install mongodb
Create file app.js
const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');
const uri = "mongodb://barry:barry#localhost:50011,localhost:50012,localhost:50013/nodetest?replicaSet=replSet&authSource=admin";
const client = new MongoClient(uri, { useUnifiedTopology: true });
const collectionName = "user_relations";
client.connect(function(err) {
const db = client.db("nodetest");
const collection = db.collection(collectionName);
const pipeline = [
{
"$match": {
"operationType": "insert",
"fullDocument.userId": "6fcfd7b3847dd9999430f1ad"
}
}
];
const stream = collection.watch(pipeline);
const changeStreamOptions = { fullDocument: "updateLookup" };
stream.on("change", stream_OnChange, changeStreamOptions);
});
function stream_OnChange(documentChange) {
console.log(documentChange.fullDocument.arrayOfFriends);
}
Probably need to change the connection string, and/or database names.
Execute using nodemon...
nodemon app.js
Insert into the MongoDB database using mongoshell...
db.user_relations.insert({userId: "6fcfd7b3847dd9999430f1ad", arrayOfFriends: [ {userId: 1, lastMessage: "Message 1"}, {userId: 1, lastMessage: "Message 2"}] })
See output in nodemon window
[nodemon] starting `node app.js`
[
{ userId: 1, lastMessage: 'Message 1' },
{ userId: 1, lastMessage: 'Message 2' }
]
Conclusion and Evaluation
Notice the output is only part of the full document? This is because the stream_OnChange method is referring to the sub fields directly. Is this what you are after?
EDIT 2021-08-29
Per comments by the OP, the desire is to see an item that is added to an array, presumably by a $push operation, but show only that item. The strategy for this is to NOT look at the object "fullDocument" but instead look at the operation in the changestream.
To illustrate this, I have modified the function stream_OnChange(documentChange) as described above in the file app.js.
function stream_OnChange(documentChange) {
console.log("##### FULL PAYLOAD #####");
console.log(documentChange);
console.log("##### END FULL PAYLOAD #####");
try {
var updatedFields = documentChange.updateDescription.updatedFields;
Object.keys(updatedFields).forEach( function (key1, index1, _array1) {
var value1 = updatedFields[key1];
console.log(key1 + ": " + value1);
Object.keys(value1).forEach( function (key2, index2, _array2) {
var value2 = value1[key2];
console.log(key2 + ":" + value2);
});
});
}
catch(e) {
}
}
Here, I am parsing the response of the update peeling apart the updateDescription and looking specifically at the updatedFields.
For example, lets say I push a new object to my array...
db.user_relations.updateOne({ userId: "6fcfd7b3847dd9999430f1ad" }, { $push: { arrayOfFriends: { userId: 1, lastMessage: "Message 3" } } }
)
Example of output:
##### FULL PAYLOAD #####
{
_id: {
_data: '82612BD118000000012B022C0100296E5A10041B035F339E2B48B6A3A5E707D801316A46645F69640064612BD10D69B433970757F4EF0004'
},
operationType: 'update',
clusterTime: new Timestamp({ t: 1630261528, i: 1 }),
ns: { db: 'nodetest', coll: 'user_relations' },
documentKey: { _id: new ObjectId("612bd10d69b433970757f4ef") },
updateDescription: {
updatedFields: { 'arrayOfFriends.2': [Object] },
removedFields: [],
truncatedArrays: []
}
}
##### END FULL PAYLOAD #####
arrayOfFriends.2: [object Object]
userId:1
lastMessage:Message 3
To catch updates I needed to modify app.js client connect method - specifically the pipeline definition...
client.connect(function(err) {
const db = client.db("nodetest");
const collection = db.collection(collectionName);
const pipeline = [
{
"$match": {
"operationType": "update"
}
}
];
const stream = collection.watch(pipeline);
const changeStreamOptions = { fullDocument: "updateLookup" };
stream.on("change", stream_OnChange, changeStreamOptions);
});

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.