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.
Related
I have a "countries" table with the following fields:
id: integer
name: json
Field "name" stores value as:
{ "en": "Germany", "de": "Deutschland" }
I wrote the following rule:
'country' => 'nullable|string|max:255|exists:countries,name->en'
but it doesn't work like that. How do I make it work?
MariaDB 10.1.36 / Laravel 5.7
Laravel 5.7 doesn't support JSON queries on MariaDB. This will be fixed in Laravel 5.8.
In the meantime, you can use this package: https://github.com/ybr-nx/laravel-mariadb
I dont think this is possible with the default validation rules from laravel.
You would have to add a where clause to the exists rule or create your own custom validation rule for this:
Using where clause:
public function rules()
{
$country = $this->country;
return [
'country' => [
'nullable',
'string',
'max:255',
Rule::exists('countries')->where(function ($query) use ($country) {
return $query->where(DB::raw('JSON_EXTRACT(`name`, "$.en")'), $country);
})
],
];
}
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"
}
}
}
}'
I imported my MySQL database to MongoDB using MongoVUE.
First let me make an example of my tables:
Table0 = 1,500 entries
Table1 = 120,000 entries
Table2 = 18,000,000 entries
Table0 -> hasMany -> Table1 entries
Table1 -> hasMany -> Table2 entries
All tables have a _id key now but after the import both tables still have an id key from MySQL.
How do I updated table2's keys table1_id to match table1's _id key? Is it doable using a Mongo query or should I have to write a script for that? (The only language I know is PHP and Javascript/NodeJS)
Update 1
Using user #profesor79 answer I made this query where table1 = market_item_histories and table2 = market_items
db.market_item_histories.aggregate([
{
$lookup: {
from:"market_items",
localField: "market_item_id",
foreignField: "id",
as: "market_items_docs"
}
},
{
$unwind:"$market_items_docs"
},
{
$project: {
_id:1,
oldId:"$market_item_id",
market_item_id:"$market_items_docs._id",
date:1,
price:1,
amount:1,
created_at:1,
updated_at:1
}
},
{
$out:"marketItemHistories"
}
])
When running that code I get this Error:
assert: command failed: {
"errmsg" : "exception: Unrecognized pipeline stage name: '$lookup'",
"code" : 16436,
"ok" : 0
} : aggregate failed
Error: command failed: {
"errmsg" : "exception: Unrecognized pipeline stage name: '$lookup'",
"code" : 16436,
"ok" : 0
} : aggregate failed
at Error (<anonymous>)
at doassert (src/mongo/shell/assert.js:11:14)
at Function.assert.commandWorked (src/mongo/shell/assert.js:254:5)
at DBCollection.aggregate (src/mongo/shell/collection.js:1278:12)
at (shell):1:26
2016-04-29T14:13:48.223+0000 E QUERY Error: command failed: {
"errmsg" : "exception: Unrecognized pipeline stage name: '$lookup'",
"code" : 16436,
"ok" : 0
} : aggregate failed
at Error (<anonymous>)
at doassert (src/mongo/shell/assert.js:11:14)
at Function.assert.commandWorked (src/mongo/shell/assert.js:254:5)
at DBCollection.aggregate (src/mongo/shell/collection.js:1278:12)
at (shell):1:26 at src/mongo/shell/assert.js:13
this is a nice real life problem.
To get this done we can use aggregation framework and "join" tables, then write results in new collection.
After that the source can be renamed/deleted and our out can be renamed too.
This was done using mongo console.
Please find solution for joining table1 with table0, and use this to perform on others joins.
db.table1.aggregate([
{
$lookup:{
from:"table0",
localField: "table0_Id", // this is our join source
foreignField: "id", // this id field in table0 collection
as: "table0_docs"
}
},
{
$unwind:"$table0_docs"
},
{
$project:{
// very important list all fields here
_id:1,
data:1,
oldId:"$table0_Id",
referenceID:"$table0_docs._id",
}
},
{
$out:"newCollectionName"
}
])
AND OUTPUT DOCUMENT
{
"_id" : ObjectId("57234f5de63d33670e521892"),
"data" : "22",
"oldId" : 1,
"referenceID" : ObjectId("57234f33e63d33670e52188e")
}
Any comments welcome!
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) { ... });
I am implementing an application using Sequelize to handle communication with the database.
I have a number of users in the database and I want to implement some search-functionality which allows users to find other users based on their full name.
A user has (amongst other attributes) a firstName and a lastName in its model.
A user who is looking for another user can search for "John Doe", where John is the first name and Doe is the last name.
Unfortunately, the first name and last name are stored in separate fields in my model. Because of this, I need to concatenate the firstName and lastName field in the "where"-clause as I tried below.
In the where-clause I am just concatenating firstName and lastName and then check whether that is "like" the full name that is passed as the argument name. I think the intention of this code below is clear. It is however not working (error says it doesn't expect the '(' after concat so this syntax isn't allowed). Is there an easy trick to do this or should I write my own query using sequelize.query?
var findUserByName = function(name) {
return models.User.find({where: {concat(firstName,' ',lastName): like: name}});
}
This you can try in where clause
where: {
$and: [
Sequelize.where(
Sequelize.fn('concat', Sequelize.col('firstName'), ' ', Sequelize.col('lastName')), {
like: '%'+name+'%'
}
)
]
}
You could do that like this:
User.find({
where: {
$or: [
name: {
$like: ['%', firstName, '%'].join('')
},
lastName: {
$like: ['%', lastName, '%'].join('')
}
]
}).success(function (user) {});