Translate MYSQL query to mongodb using $Lookup - mysql

I am new to Mongodb and I have to move my SQL Queries to mongodb now. I read the document and gained enough knowledge on writing mongodb QUeries but coming from MYSQL it will take time to get expertise on framing Mongo Queries.
I am trying to convert this query to Mongo for now using $Lookup
select * from orig_tbl emas
inner join cust-tbl_after_cleanup tmclient
on emas.state = tmclient.province
and emas.cons_city = tmclient.city
where
emas.state = 'VT' and
emas.can_match_address like concat('%',tmclient.street,'%')
and emas.can_cmp_name like concat('%',tmclient.name,'%')
and emas.can_match_address like concat('%',tmclient.house_num,'%')
and emas.can_match_address like concat('%',tmclient.postal_code,'%')
and emas.cons_city like concat('%',tmclient.city,'%')
and emas.State like concat('%',tmclient.province,'%')
group by tmclient.id,tmclient.name
As you can see I'm doing an inner join on multiple conditions and then doing a partial string match on number of cloumns. From the document I got to know how to do a multiple condition join but not sure how to do partial string match
Code so far:
aggregate(
[
{
'$match' : { 'name' : 'Walmart' }
},
{
'$lookup':
{
'from': 'entity_map_all_states',
'let': { 'order_city': "$city", 'order_qty': "$province" },
'pipeline': [
{ '$match':
{ '$expr':
{ '$and':
[
{ '$eq': [ "$cons_city", "$$order_city" ] },
{ '$eq': [ "$State", "$$order_qty" ] }
]
}
}
}
],
'as': "stockdata"
}
}
] )

Related

Convert SQL query to sequelize query with multiple tables

I've been at this for several days attempting to convert what I thought was a relatively simple SQL query into sequelize format. I cannot seem to figure it out for the life of me. I'm relatively new to sequelize, and my SQL skills can use some help as well.
Any help is greatly appreciated, thanks!
Here is the SQL query I have (which works for what I'm attempting to do) which I'm struggling to get to work in sequelize:
SELECT
book.id,
book.author,
book.title,
book_type.type,
book_sub_type.sub_type,
book_location.location,
book_language.language
FROM book
INNER JOIN book_type ON book.book_type_id = book_type.id
INNER JOIN book_sub_type ON book.book_sub_type_id = book_sub_type.id
INNER JOIN book_location ON book.book_location_id = book_location.id
INNER JOIN book_language ON book.book_language_id = book_language.id
WHERE
book.author LIKE '%history%' OR
book.title LIKE '%history%' OR
book_type.type LIKE '%history%' OR
book_sub_type.sub_type LIKE '%history%' OR
book_language.language LIKE '%history%' OR
book_location.location LIKE '%history%'
ORDER BY book_type.type, book_sub_type.sub_type;
Here is as far as I have gotten (this sequelize query returns 0 results because it is searching for the substring "history" in all columns, instead of at least one column):
const books = await Book.findAll({
where: {
[Op.or]: [
{author: { [Op.substring]: 'history' }},
{title: { [Op.substring]: 'history' }}
]
},
attributes: ['id', 'author', 'title'],
include: [
{
model: BookType,
attributes: ['type'],
where: {
type: { [Op.substring]: 'history' }
}
},
{
model: BookSubType,
attributes: ['sub_type'],
where: {
sub_type: { [Op.substring]: 'history' }
}
},
{
model: BookLanguage,
attributes: ['language'],
where: {
language: { [Op.substring]: 'history' }
}
},
{
model: BookLocation,
attributes: ['location'],
where: {
location: { [Op.substring]: 'history' }
}
},
]
});
My schema is as follows:
`book` table columns:
`id`, `author`, `title`, `book_type_id`, `book_sub_type_id`,
`book_language_id`, `book_location_id`
`book_type` table columns:
`id`, `type`
`book_sub_type` table columns:
`id`, `sub_type`
`book_location` table columns:
`id`, `location`
`book_language` table columns:
`id`, `language`
In sequelize, I have the following relationships established:
Book.belongsTo(BookType);
Book.belongsTo(BookSubType);
Book.belongsTo(BookLanguage);
Book.belongsTo(BookLocation);
BookType.hasMany(Book);
BookSubType.hasMany(Book);
BookLanguage.hasMany(Book);
BookLocation.hasMany(Book);
The output should be 7 columns:
book.id, book.author, book.title, book_type.type, book_sub_type.sub_type, book_location.location, book_language.language
Sequelize build a SQL with a conditions in JOINs, so this is not good aproach. You should remove all where conditions from includes. There was a way in a sequelize <4.0.0 to write conditions to subquery using syntax
where: {
$or: [{
'$book.sub_type$$': 'history'
}, {
'$book_type.type$': 'history'
}]
}
but I think this is not longer supported. Only way would be a custom query or use a sequelize literal in where object.
where: {
[Op.or]: [{
Sequelize.literal(`book_type.type LIKE ${history}`)
}, {
Sequelize.literal(`book_sub_type.sub_type LIKE ${history}`)
}]
}
Keep in mind that with this approach there is a risk of SQL injection so you should validate an input or use some escape character strategy. Check sequelize raw queries and seqeulize literal

how can I write this query in elasticsearch?

how can I write this mysql query in elasticsearch ?
SELECT *,count(products.store_id)
FROM stores
INNER JOIN products
ON stores.store_id=products.store_id
group by stores.store_id;
Elasticsearch is not exactly a database, it's a search engine and hence it supports very limited JOIN operations (parent-child queries).
If you want to execute the above query then you will have to rework the schema and try to have the data in one index (doesn't matter even if it's not in 2NF/3NF). Maybe you can index store_id along with each product document.
Now, coming back to the query, if you want to execure the above query on let's say one index then you can do it using TERMS aggregation. It will give you count of products grouped by store id, the request would look like this:
$ curl -XPOST 'http://localhost:9200/products/_search?search_type=count' -d '{
"query" : {
"filtered" : {
"filter" : {
"bool" : {
"must" : [
{ "term" : {"product_type" : "sometype"}}
]
}
}
}
},
"aggs" : {
"products" : {
"terms" : {
"field" : "store_id"
}
}
}
}'

CouchDB get all databases and their last changes

I know that i can get all databases with
GET _all_dbs
and also the last change of a database by
GET /{db}/_changes?descending=true&limit=1
the result will be like:
{
"results":[
{
"seq":112,
"id":"20e3480f5db4802d94a8193ac2246ae7",
"changes":[
{
"rev":"2-fb8204608047ce016282acbf3239cd01"
}
],
"deleted":true
}
],
"last_seq":112
}
Now is it possible to combine these statements to get something like:
{
"results":[
{
"db1":"1-fb8204608047ce016282acbf3239cd01"
},
{
"db2":"2-fb8204608047ce016282acbf3239cd02"
},
{
"db3":"2-fb8204608047ce016282acbf3239cd03"
},
{
"db4":"2-fb8204608047ce016282acbf3239cd04"
}
]
}
where "db1" is a database name and "2-fb8204608047ce016282acbf3239cd04" is the last _rev of the database.
There is no mechanism to make any query across multiple database in couchdb.
You can however do this from your application by joining the result of multiple queries.

Make a join query in loopback.io

I am trying to build a simple application using loopback.io as process of my learning. I have set up the project, created models and apis are working fine.
Now I am trying to create a custom api which can get the data from two different models by making a join query. So i have a two models
stories : id, title, noteId
notes : id , desc
i have stories.js file as
module.exports = function(Stories) {
Stories.list = function(cb) {
// make a join query
};
Stories.remoteMethod(
'list', {
http: {
path: '/list',
verb: 'get'
},
returns: {
arg: 'list',
type: 'array'
}
}
);
};
In general i will make a join in php api but here i am bit confused.Can i pass a raw query to database here or does loopback has some different way of achieving this. Any help would be appreciated.
You don't need to pass sql query. You can query data using PersistedModel find method by using include filter
In order to use include filter you have to create model relation.
For example:
Note relation:
"relations": {
"stories": {
"type": "hasMany",
"model": "Story",
"foreignKey": "noteId"
}
},
Query:
Note.find({include: ['stories']}, function(err, data) { ... });

Convert Mysql query to Mongodb find()

I have a mongodb collection structured like this:
{ "client" : "CLIENTIDHERE", "amount" : 90, "invoice": "SOMEIDHERE", "date" : ISODate("2014-07-09T11:13:49.273Z") }
And need to select somehow all the payments made from a client.
In mysql I would do something like this, but with mongodb I have really no clue.
SELECT SUM(amount) payments,client FROM invoices GROUP BY client;
What I tried:
db.invoices.find({
$group: {
amount: {$sum: "$amount"}
}
}, {
$project:{
amount: "$amount",
client: "$client"
}
})
But it didn't work. What did I do wrong?
EDIT: I get the following error:
error: { "$err" : "Unsupported projection option: amount", "code" : 13097 }
Your $group step doesn't define what to GROUP BY. MongoDB's equivalent for the SQL GROUP BY is the _id field of the $group statement which is missing from your query. Also, when you want to use aggregation, you need to use .aggregate( instead of .find(.
db.invoices.aggregate({
$group: {
_id: "$client",
amount: { $sum: "$amount"}
}
});
This will write the client into the _id field. When you would rather want to have the field named client, you can fix that in the $project step, but otherwise the projection is not required in this case.