Execute Logical Operator Filters On GraphQL OnlyOn JSON Objects - graphql-js

Thank you for help. I am trying to execute AND/OR operator in GraphQL without Database.
Below is Query need to execute on dataset not database. Please understand, I don't have authority to connect to any database.
{
customVisualsData(_filter: {and: [{expression: {field: "Country", like: "Canada"}},{expression: {field: "Profit", gt: "5000"}}]}) {
Country
DiscountBand
Product
Segment
Profit
}
}
Transform dataset/JSON Object look like this.
[
{
"Country": "Canada",
"DiscountBand": "High",
"Product": "Paseo",
"Segment": "Government",
"COGS": 1477815,
"GrossSales": 2029256,
"ManufacturingPrice": 70,
"UnitsSold": 12230.5,
"Profit": 300289.99999999994
},
{
"Country": "United States of America",
"DiscountBand": "High",
"Product": "VTT",
"Segment": "Small Business",
"COGS": 1461250,
"GrossSales": 1753500,
"ManufacturingPrice": 750,
"UnitsSold": 5845,
"Profit": 74288
}
]
Schema Builder, I used to create GraphQL Query builder.
var schema = buildSchema(`
type customVisualObject {
Country: String
DiscountBand: String
Product: String
Segment: String
COGS: Float
GrossSales: Float
ManufacturingPrice: Int
UnitsSold: Float
Profit: Float
}
type Query {
customVisualsData(_filter: FilterInput): [customVisualObject]
}
input FilterExpressionInput {
field: String!
eq: String
gt: String
gte: String
like: String
}
input FilterInput {
expression: FilterExpressionInput
and: [FilterInput!]
or: [FilterInput]
not: [FilterInput!]
}
`);
Please let me know, if anyone know How to set resolver for this on graphQL?
Does anyone one know JSON-ata Or GraphQL library to execute such complex Query on JSON Object Not databse?
I appreciate your help.

Related

Mongodb find documents with a specific aggregate value in an array

I have a mongo database with a collection of countries.
One property (currencies) contains an array of currencies.
A currency has multiple properties:
"currencies": [{
"code": "EUR",
"name": "Euro",
"symbol": "€"
}],
I wish to select all countries who use Euro's besides other currencies.
I'm using the following statement:
db.countries.find({currencies: { $in: [{code: "EUR"}]}})
Unfortunately I'm getting an empty result set.
When I use:
db.countries.find({"currencies.code": "EUR"})
I do get results. Why is the first query not working and the second one succesfull?
The first query is not working as it checks whether the whole currency array is in the array, which is never true.
It is true when:
currencies: {
$in: [
[{
"code": "EUR",
"name": "Euro",
"symbol": "€"
}],
...
]
}
I believe that $elemMatch is what you need besides the dot notation.
db.collection.find({
currencies: {
$elemMatch: {
code: "EUR"
}
}
})
Sample Mongo Playground
MongoDB works in the same way if the query field is an array or a single value, that's why the second one works.
So why the first one doesn't work? The problem here is that you are looking for an object that is exactly defined as {code: "EUR"}: no name or symbol field are specified. To make it work, you should change it to:
db.getCollection('countries').find({currencies: { $in: [{
"code" : "EUR",
"name" : "Euro",
"symbol" : "€"
}]}})
or query the subfield directly:
db.getCollection('stuff').find({"currencies.code": { $in: ["EUR"]}})

Go-MongoDriver decoding JSON array weirdly

Heyho party people,
I've recently took up learning Go and started working on a small side project which includes a API written using the Go Fiber library.
All the necessery data is stored in MongoDB with the following schema
{
"ObjectId": {
"name": "name",
"url": "url",
"dateAdded": "date",
"data": [{
"timestamp 1": "price 1"
},
{
"timestamp 2": "price 2"
}
]
}
}
The item type looks like this:
type Item struct {
ID primitive.ObjectID `json:"_id" bson:"_id"`
Name string `json:"name" bson:"name"`
URL string `json:"url" bson:"url"`
DateAdded string `json:"dateAdded" bson:"dateAdded"`
Data []interface{} `json:"data" bson:"data"`
}
Whenever I query a stored item with
err = collection.FindOne(context.TODO(), filter).Decode(&item)
each map inside of the data-array is wrapped in another array =>
{ test url 2021-04-16 [[{2021-04-16 99.99}] [{2021-04-17 109.99}]] }
instead of
{ test url 2021-04-16 [{2021-04-16 99.99}, {2021-04-17 109.99}] }
Does anybody have an idea on how to fix this?
Thanks in advance!
OK, I've found a way to fix this behaviour for my use case.
As mentioned above, the MongoDB-driver for Go wraps each entry of an array into another respective array, which leads to a nested array.
After trying around for some time I found out, that inserting the document into your collection like the following example,
db.collection.insertOne({ name: "Name", url: "URL", dateAdded: "2021-04-25", data: { "2021-04-25": 9.99, "2021-04-26": 19.99 } })
then the result of a query performed in your program looks like this:
{ ObjectID("60858245f8805dc57a716500") Name URL 2021-04-25 [{ 2021-04-25 9.99 } { 2021-04-26 19.99 }] }
This means, that the JSON-schema should look like this
{
"ObjectId": {
"name": "name",
"url": "url",
"dateAdded": "date",
"data": {
"2021-04-25": 9.99,
"2021-04-26": 19.99
}
}
}
Sadly, I was not able to find out what is actually causing this odd behaviour, but I hope this helps anybody encountering this (or a similar) problem.
EDIT
Changing the type of the Data-field to []bson.M, as mkopriva said in the comments below, fixed it.
type Item struct {
ID primitive.ObjectID `json:"_id" bson:"_id"`
Name string `json:"name" bson:"name"`
URL string `json:"url" bson:"url"`
DateAdded string `json:"dateAdded" bson:"dateAdded"`
Data []bson.M `json:"data" bson:"data"`
}
This way the original JSON-schema does not have to be adapted to the workaround.
{
"ObjectId":{
"name":"name",
"url":"url",
"dateAdded":"date",
"data": [
{
"2021-04-25": 9.99
},
{
"2021-04-26": 19.99
}
]
}
}

MongoDB Project - return data only if $elemMatch Exist

Hello Good Developers,
I am facing a situation in MongoDB where I've JSON Data like this
[{
"id": "GLOBAL_EDUCATION",
"general_name": "GLOBAL_EDUCATION",
"display_name": "GLOBAL_EDUCATION",
"profile_section_id": 0,
"translated": [
{
"con_lang": "US-EN",
"country_code": "US",
"language_code": "EN",
"text": "What is the highest level of education you have completed?",
"hint": null
},
{
"con_lang": "US-ES",
"country_code": "US",
"language_code": "ES",
"text": "\u00bfCu\u00e1l es su nivel de educaci\u00f3n?",
"hint": null
}...
{
....
}
]
I am projecting result using the following query :
db.collection.find({
},
{
_id: 0,
id: 1,
general_name: 1,
translated: {
$elemMatch: {
con_lang: "US-EN"
}
}
})
here's a fiddle for the same: https://mongoplayground.net/p/I99ZXBfXIut
I want those records who don't match $elemMatch don't get returned at all.
In the fiddle output, you can see that the second item doesn't have translated attribute, In this case, I don't want the second Item at all to be returned.
I am using Laravel as Backend Tech, I can filter out those records using PHP, but there are lots of records returned, and I think filtering using PHP is not the best option.
You need to use $elemMatch in the first parameter
db.collection.find({
translated: {
$elemMatch: {
con_lang: "IT-EN"
}
}
})
MongoPlayground

spring-data-mongodb document design options - array vs dynamic field (i.e. map)

I am designing a document structure and use spring-data-mongodb to access it. The document structure is to store device profile. Each device contains modules of different types. The device can contains multiple modules of the same type. Module types are dynamic as new type of modules are created sometimes.
Please note: I try not to write custom queries to avoid boilerplate code. But, some custom queries should be fine.
I come out with two designs:
the first one use dynamic field (i.e. map). Semantics is better but seems harder to query/update using spring-data-mongodb.
{
deviceId: "12345",
instanceTypeMap: {
"type1": {
moduleMap: {
"1": {field1: "value",field2: "value"},
"2": {field1: "value",field2: "value"}
}
},
"type2": {
moduleMap: {
"30": {fielda: "value",fieldb: "value"},
"45": {fielda: "value",fieldb: "value"}
}
}
}
the second one use array and query/update seems more in-line with spring-data-mongodb.
{
deviceId: "12345",
allInstances: [
{
type: 1,
modules: [
{
id: 1,
field1: "value",
field2: "value"
},
{
id: 2,
field1: "value",
field2: "value"
}
]
},
{
type: 2,
modules: [
{
id: 30,
fielda: "value",
fieldb: "value"
},
{
id: 45,
fielda: "value",
fieldb: "value"
}
]
}
]
}
I am inclined to use array. Is it better to use array instead of dynamic field with spring-data-mongodb. I did some search on-line and found people mentioned that query for key (i.e. in map) is not as easy in spring-data-mongodb. Is that a correct statement? Do I miss anything? Thank you in advance.
I ended up with the design as below. I use one device-instance-type per document. Because, in some scenario,
updates are done on many modules of the same instance type. Those updates can be aggregated as just one database update.
The redundant "moduleId" field is also added for query purpose.
{
deviceId: "12345",
instanceTypeId: "type1",
moduleMap: {
"1": {
moduleId: "1",
field1: "value",
field2: "value"
},
"2": {
moduleId: "2",
field1: "value",
field2: "value"
}
}
}
Now, I can use spring-data-mongodb's query:
findByDeviceId("12345");
findByDeviceIdAndInstanceTypeId("12345","type1");
findByDeviceIdAndInstanceTypeIdAndModuleMapModuleId("12345","type1","1");

Find all objects, that's nested properties have desired value

I have collection with the following (sample) documents:
{
"label": "Tree",
"properties": {
"height": {
"type": "int",
"label": "Height",
"description": "In meters"
},
"coordinates": {
"type": "coords",
"label": "Coordinates"
},
"age": {
"type": "int",
"label": "Age"
}
}
}
Keys in the properties attribute are different for almost each of the documents in collection.
I want to find all documents that have at least one property of given type.
What I'm looking for is to query this for {"properties.*.type": "coords"}. But this is not working as it is only my invention of mongo query.
Every help I was able to find concerned the $elemMatch operator which I can not use here because properties is an object, not an array.
Hi as per my knowledge in mongodb not provide this kind of search. So for finding this first I separated out all keys using map-reduce and then find query form so below code will help you
var mapReduce = db.runCommand({
"mapreduce": "collectionName",
"map": function() {
for (var key in this.properties) {
emit(key, null);
}
},
"reduce": function(key, stuff) {
return null;
},
"out": "collectionName" + "_keys"
})
db[mapReduce.result].distinct("_id").forEach(function(data) {
findkey = [];
findkey.push("properties." + data + ".type");
var query = {};
query[findkey] = "coords";
var myCursor = db.collectionName.find(query);
while (myCursor.hasNext()) {
print(tojson(myCursor.next()));
}
})
MongoDB doesn't support searches on keys - things like properties.* to match all subkeys of properties, etc. You shouldn't have arbitrary keys or keys that you don't know about in your schema, unless they are just for display, generally, because you will not be able to interact with them very easily in MongoDB.
If you do want to store dynamic attributes, the best approach is usually an array like the following:
{
"properties" : [
{
"key" : "height",
"value" : {
"type" : "Int",
"label" : "Height",
"description" : "In meters"
}
},
...
]
}
Efficient querying for your use case
find all documents that have at least one property of given type
results from an index on { "key" : 1 }:
db.test.find({ "properties.key" : { "$in" : ["height", "coordinates", "age"] } })