I'm having difficulty describing a sort of query language that I figure must exist and have a name.
Simply, you describe the data you want to receive as a data structure of paths to values and any transformations, constraints, etc.
For example, requesting this:
{:query {:title
:content
:fullname (join [:author.firstname :author.lastname] " ")
:meta {:date-created
:date-updated
:date-published}}
:limit 10
:order-by :title}
would return a list of results like:
[
{:title "dummy title 1"
:content "lorem ipsum"
:author "Jane Doe"
:meta {:date-created 2016-01-01
:date-updated 2016-01-02
:date-published 2016-01-02}}
{:title "dummy title 2"
:content "ipsum lorem"
:author "John Doe"
:meta {:date-created 2016-01-01
:date-updated 2016-01-02
:date-published 2016-01-02}}
...
]
Datalog type queries and even MongoDB queries have a similar feel but does this type of querying have a name or fit some design pattern I can better search the internet for?
I've just come across Facebook's GraphQL that seems to serve this purpose.
https://code.facebook.com/posts/1691455094417024/graphql-a-data-query-language/
And the Python Graphene library has Django support.
There is a repo with links to the various implementations: https://github.com/chentsulin/awesome-graphql
Related
Lets say you have the following schema
employee( firstname, lastname, dept)
Say we want the lastname to be uppercase for all the rows in the table (the uppercase function might be a built-in function in the DBMS, but lets assume it's a UDF)
In SQL we would have done the following
Select firstname, toUpper(lastname) as lastname, dept
From employees
What is the equivalent in mangoDB ? Knowing that we have a document employees which contains the following JSONs:
...
{ "firstname": "jhon", "lastname": "doe", "dept": "marketing"}
...
{ "firstname": "jean", "lastname": "dupont", "dept": "sales"}
...
The goal is to directly obtain the changed data using mongoDB query API, without writing extra JS code to get the job done.
I Know how to save/import a UDF in MongoDB. What I don't know is how to apply it to a result:
db.employees.find().apply_my_udf(....)
Use .aggregate() and $toUpper in a $project:
db.employees.aggregate([
{ "$project": {
"firstname": 1,
"lastname": { "$toUpper": "$firstname" },
"dept": 1,
}}
])
The aggregation framework is basically where you go for "tranformations" on data of any kind. The .find() method is really just for "plain selection" of documents and supports simple "inclusion" or "exclusion" of properties only.
If you have some familiarity with SQL, then SQL to Aggregation Mapping Chart in the core documentation is a good place to start with understanding how to apply common phrases.
Of course as an "alternative" approach you can also apply the "transform" to the data "after" the results are fetched from the server. All drivers provide some form of cursor.map() for this very purpose.
As a JavaScript shell example:
db.employees.find().map( d => Object.assign(d, { lastname: d.lastname.toUpperCase() }) )
Which essentially does the same thing, but the transformation is done as each document is retrieved from the server as opposed to transforming on the server itself.
Let's say i have records of people with names like:
[
{ name: "Joe Smith" },
{ name: "Mary Cage" },
{ name: "Jenn Blair" }
]
If i used MySQL, i'd easily do something like:
WHERE name LIKE %Smith% OR name LIKE %Blair%
That will return two records (1 for Joe Smith and 1 for Jenn Blair).
How do I do the same with Algolia? I have tried queries like Smith OR Blair but they return nothing!
Algolia has no syntax for query conditions like this, by default all terms in query will be searched in your records.
However, you can do this with the optionalWords query parameter, which Algolia will use to remove words from the query:
optionalWords="Smith Blair"
query="Smith Blair"
This will return all records matching either "Smith" or "Blair".
How can i achieve autocompleter search/results withh query dsl (QueryBuilder) ?
(api link)
Want to achieve search like :
search keyword "John D"
result:
"John Daa"
"John Derm"
"John Deerms"
I tried to use "match" and "multi match" with "phrase_prefix" type, it almost did the job but there is something wrong, since results are :
for keyword "John D" - only "John Daa" is shown, other two are missing, do not understand this part much.
for keyword "John De" - Shown are "John Derm", "John Deerms" which is OK .
The problem you have is solved by completion suggester.
I'm going to create an Inbox structure in mongodb. I have some trouble on the Inbox Schema for a multi-user message.
I thought to create something like this where Recipients contains Objects. Every object contains userId and a log to know if the message was red or not.
if it's a correct(efficient!!) structure, how can the user 456 to know if he has some message to read?
{
userId: "123"
,recipients: [ {userId:123, read:true}
,{userId:456, read:false}
,{userId:789, read:false} ]
,text: "message wrote by user 123"
}
,{
userId: "456"
,recipients: [ {userId:123, read:false}
,{userId:456, read:true}
,{userId:789, read:false} ]
,text: "message wrote by user 456"
}
This structure could work provided the CC or To list (I am assuming as being represented by the receipients list) does not grow out of control and becomes unbound.
To answer your initial question, you can use $elemMatch:
db.inbox.find({receipients:{$elemMatch:{userId:456,read:false}}})
That should be an efficient query and will return all messages that user 456 has not yet read.
We have an events calendar and here is what I am thinking for our basic mongo schema:
users
username
password
salt
events
name
description
tags[]
category
venue_id
...
venues
name
address
loc
Queries that will be done are:
Listing of distinct tags (this might be hard given current design)
events in a given tag
Event information along with the venue location
All event and venue information for a particular event
All events near me. Need to use a geo index on loc
Any feedback/ideas on if we should be nesting venues inside events or use mysql instead?
Ok, that looks pretty good. Let's construct some of the queries.
Assuming the collections are named users, events, venues:
Insert some dummy events:
db.events.insert({tags:["awesome","fun","cool"]})
db.events.insert({tags:["sweet","fun","rad"]})
Make an index (like a boss)
db.events.ensureIndex({ tags: 1 })
Listing of distinct tags (this might be hard given current design):
Nope, not hard.
db.events.distinct("tags")
[ "awesome", "cool", "fun", "rad", "sweet" ]
Events in a given tag (you meant "with a given tag" right?)
db.events.find({tags: "fun"})
{ "_id" : ObjectId("4ecc08c62477605df6522c97"), "tags" : [ "awesome", "fun", "cool" ] }
{ "_id" : ObjectId("4ecc08d92477605df6522c98"), "tags" : [ "sweet", "fun", "rad" ] }
Event information along with venue location
You can do this a couple different ways. One way would be to query for the event and subsequently query for the venue. With both documents, join (combine) the data you want manually.
OR
You can denormalize a bit and store cached venue names + locations (but not venue details like hours of operation, max occupancy, website, phone number, etc..) for a speed boost (1 query instead of 2) That method comes with the standard denormalization caveat of not being able to update your data in one place.
All event and venue information for a particular event
See above
All events near me. Need to use a geo index on loc
Two queries again, same concept as above just reverse the order.
Get the venues:
db.venues.find( { loc : { $near : [lat,lon] } } )
Get the events using the venue ids:
db.events.find( { venue : { $in : [id1,id2,id3...] } } )
Some of this stuff can be done automatically for you if you use an ODM.
Good luck!