Is there a way to control auto generated Elastic Search Index with amplify GraphQL transform #searchable annotation? - annotations

I am building a graphQL api with schema and annotations to use AWS Amplify's GraphQL transform. How can I control what kind of ES index it produces behind the scene?
This is a simple API that provides search functionality based on the, lets say, "5 km radius from the current location", timestamp and other keywords. The keywords search work absolutely fine but not the geospatial search. As per my research, for doing geospatial search, one needs to have a specific type of schema in ES. Here is my schema:
type User #model {
id: ID!
deviceID: [String!]
posts: [Post] #connection(name: "UserPosts")
comments: [Comment] #connection(name: "UserComments")
}
type Post #model #searchable {
id: ID!
items: String!
latitude: Float
longitude: Float
user: User #connection(name: "UserPosts")
comments: [Comment] #connection(name: "PostComments")
}
type Comment #model {
id: ID!
content: String
timestamp: AWSDateTime
location: String
post: Post #connection(name: "PostComments")
user: User #connection(name: "UserComments")
}
The query with lat, lon and distance to find "Posts" should return valid results.

The short answer to that is no.
The #searchable annotation and AppSyncs functionalities within ES are super limited out of the box. You can't even pass in fuzzy_matches.
I guess the way to go is to implement it yourself. You can modify the resolvers and thus also modify the ES search query. However, the resolvers are written in VST. Which might be not so easy to dig in.

Related

Best practices with connecting data from 2 models

I've got two models: Note and Profile. Note contains foreign key of connected profile as you can see below.
Note: {
profile_id: String,
date: String,
content: String,
}
Profile: {
id: String,
name: String,
profilePicture: String
}
I want to get all notes and also name and profile picture of note.
In this situation should I:
get all notes and all profiles and then join them locally in for loop,
get all notes and then in for loop ask DB for name and picture of matching profile,
other option
Which way is recomended?
Take a look at mongoose's Populate. You can declare a Schema property with type: Schema.Types.ObjectId, ref: 'Profile'. When you run a Query you can .populate() this field with the corresponding document.

RESTful API design advice on getting all A associated with B

I'm trying to design a RESTful API as a side project.
I am also using MongoDB as database
(I'm new to NoSQL design, so I need help, If I have misunderstanding in how documents should be designed).
I have example entities as following:
Event {
id: string
name: string
date: date
location: location
subgroups: group[]
}
Group {
id: string
owners: user[]
members: user[]
parentEvent: event
posts: post[]
}
User {
id: string
Name: string
attendingGroups: group[]
owningGroups: group[]
}
post {
id: string
parentgroup: Group
}
location {
id: string
city: string
}
For above example,
Should I have a designated get call for having all groups associated with the user?
or should I get a user and get the associated groups from the user retrieved?
Depends how you design it. You can embed resources in other resources to save you from N+1 select problem, nothing is against with that.
Hal+json format is the format you should be embedding resources.
In REST you can even have ?_embed=groups parameter to embed or not.
Embedding or not embedding is up to your applications needs, not embedding way = you should design a filter like /groups?user=eralpb to get the groups. Or sub-resources work as well like /users/eralpb/groups should only return my groups.

How to implement a many-to-many collection in meteor+mongo such that the collection is searchable and/or sortable by all possible fields?

I am trying to implement a collection in meteor/mongo which is of following nature:
FIRST_NAME-------LAST_NAME-------------CLASSES----------PROFESSORS
----------A-----------------------B------------------------------a---------------------b
-------------------------------------------------------------------c---------------------d
-------------------------------------------------------------------e---------------------f
-------------------------------------------------------------------g---------------------h
-------------M-------------------------N------------------------c---------------------d
-------------------------------------------------------------------p---------------------q
-------------------------------------------------------------------x---------------------q
-------------------------------------------------------------------m---------------------n
-------------------------------------------------------------------r---------------------d
So as above, a person can take multiple classes and a class can have multiple people. Now, I want to make this collection searchable and sortable by all possible fields. (Also that one professor can teach multiple classes.)
Searching by FIRST_NAME and LAST_NAME is easy in above shown model. But, I should be able to see all student depending on the class I select. I would also want to see list of classes sorted in alphabetical order and also the people enrolled in corresponding classes?
Can you please let me know how to approach this in a meteor/mongo style? I would also be glad if you could lead me to any resources available on this?
You are describing one of the typical data structures which are better suited for a relational database. But don't worry. For reasonably sized data sets it is quite workable in MongoDB too.
When modelling this type of structure in a document database you use embedding, which does lead to data duplication, but this data duplication is typically not a problem.
Pseudo-code for your model:
Collection schoolClass: { // Avoid the reserved word "class"
_id: string,
name: string,
students: [ { _id: string, firstName: string, lastName: string } ],
professor: { _id: string, firstName: string, lastName: string }
}
Collection student: {
_id: string,
firstName: string,
lastName: string,
classes: [ { _id: string, name: string } ]
}
Collection professor: {
_id: string,
firstName: string,
lastName: string,
classes: [ { _id: string, name: string } ]
}
This gives you easily searchable/sortable entry points to all objects. You only follow the "relation" _id to the next collection if you need some special data from an object. All data needed for all documents in the common queries should be present in the Collection the query is run on.
You just need to make sure you update all the relevant collections when an object changes.
A good read is https://docs.mongodb.com/manual/core/data-modeling-introduction/

Ember & Firebase data query from bottom-up approach?

My data model is described below. I would like to write a queries that would return:
list of reviews in a given department
list of specific types of training
list of reviews in a given college
So starting from the department, here is what I tried to do:
Query for reviews in the department:
var department = this.store.findRecord('department',params.department_id)
var reviews = this.store.query('review' {'faculty.department':department});
Query for specific trainings:
var design = this.store.query('training',{'faculty.department':department, filter:{type:'ATC Design Course (DQOC)'}});
Query for the reviews of all the faculty working in a given college:
var college = this.get('college');
var cid = college.getProperties("id").id
var reviewQuery = store.query('review',{'faculty.department.college._id':college._id});
var trainingQuery = store.query('training',{'faculty.department.college._id':college._id});
Neither of the queries give me results I am looking for. It seems they all evaluate to query that finds all results of given model type, for example query below returns all training models of all types.
var design = this.store.query('training',{'faculty.department':department, filter:{type:'ATC Design Course (DQOC)'}});
I need a help with rewriting the queries so they will return correct results. What is the best practice in this case, and how should I implement it?
Is it possible to query model bottom app starting from reviews->faculty->department->college?
Alternatively I could go with top down approach, and query all departments, instructors and so on with some nested for loop structure but would like to go other way if possible. How would this query look like?
I will appreciate any help.
Colleges:
export default DS.Model.extend({
name: DS.attr('string'),
departments: DS.hasMany('department')
});
Departments
export default DS.Model.extend({
name: DS.attr('string'),
faculty:DS.hasMany('faculty'),
college: DS.belongsTo('college')
});
Faculty:
export default DS.Model.extend({
profile_image:DS.attr('string'),
firstname: DS.attr('string'),
lastname: DS.attr('string'),
salutation: DS.attr('string'),
email: DS.attr('string'),
department: DS.belongsTo('department'),
reviews: DS.hasMany('review'),
training: DS.hasMany('training')
});
Reviews
export default DS.Model.extend({
faculty: DS.belongsTo('faculty'),
courseName:DS.attr('string'),
internalDate:DS.attr("date"),
externalDate:DS.attr("date"),
funDate:DS.attr("date"),
recertificationDate:DS.attr("date")
});
Training
export default DS.Model.extend({
type: DS.attr('string'),
faculty: DS.belongsTo('faculty'),
date:DS.attr("date")
});
FIRST EDITS Question
How can I get all reviews in a given college?
var rquery = store.query('review', {faculty.department.college._id : college._id})
or
var rquery = store.query('review', {faculty.department.college : college})
gives me a syntax error.
SyntaxError: quality-online/components/quality-chart.js: Unexpected
token (50:44)
when using faculty.department.college._id, the query function starts looking for the definition of faculty object in your function and tries to access the value of department.college._id from it and uses the value returned by faculty.department.college._id as the parameter key. And this is the issue. As it seems the faculty object is not defined as well as this is not the right approach for passing a parameter either.
If you want to send some parameter to backend send it as 'college_id' or as mentioned in the comments above as 'faculty.department.college'. The only conditions are that it should be a string and it is handled properly at your server side code.

Does Mongoose only support embedded documents in arrays?

I have some data in MongoDB that looks like this:
{
name: "Steve",
location: {
city: "Nowhere, IL",
country: "The United States of Awesome"
}
}
I’m using objects to organize common data structures (like locations), which in Mongoose might map nicely to Schemas. Unfortunately, they don't appear to really work in Mongoose.
If I just embed an object, like this:
{
name: String,
location: {
city: String,
country: String
}
}
It appears to work, but exhibits some bizarre behavior that causes problems for me (e.g. instance.location.location returns location, and subobjects inherit methods from the parent schema). I started a thread on the Mongoose list, but it hasn’t seen any action.
If I embed a Schema, like this:
{
name: String,
location: new Schema({
city: String,
country: String
})
}
…my application doesn’t start (Schema isn’t a type supported by Mongoose). Ditto for
{
name: String,
location: Object
}
…which wouldn’t be ideal, anyway.
Am I missing something or do my schemas not jive with Mongoose?
I did something similar:
var Topic = new Schema({
author : ObjectId
, title : String
, body : String
, topics : [Topic]
});
This worked fine in my tests. However, removing the array brakets resulted in an error. Looks like a bug to me.
https://github.com/LearnBoost/mongoose/blob/master/lib/mongoose/schema.js#L185
Dumping types, I only get String, Number, Boolean, DocumentArray, Array, Date, ObjectId, Mixed -- which appears to be on purpose, schema/index.js doesn't look like it dynamically registers new Schemas to the list of types, so I am guessing this isn't a supported use case, yet.
https://github.com/LearnBoost/mongoose/issues/188
"Embedding single docs is out of the question. It's not a good idea (just use regular nested objects)"
Josh
It looks like this was a bug, it’s been fixed in Mongoose 2.0!