I'm new to MDX, basically I need to serialize the SSAS MDX result to a JSON object.
MDX Query:
SELECT
(
[Measures].[Max Available]
) ON COLUMNS
, NON EMPTY
(
[Application].[Product].Children * [Application].[Application Name].Children
) DIMENSION PROPERTIES MEMBER_CAPTION ON ROWS
FROM [Applications]
Let's say I have a MDX result that looks like:
__________________________________
| | | Measure1 |
| Product1 | Feature1 | 1 |
| Product1 | Feature2 | 1 |
| Product1 | Feature3 | 10 |
| Product2 | Feature1 | 1 |
| Product2 | Feature2 | 1 |
| Product3 | Feature1 | 1 |
| Product3 | Feature2 | 1 |
| Product3 | Feature3 | 1 |
| Product3 | Feature4 | 1 |
I need to create a JSON object that looks like (I don't need the Measurement values, I just used them to get valid list of products and features in the MDX Heirarchy):
[
{
"product":"Product1",
"feature":[
"Feature1",
"Feature2",
"Feature3"
]
}, {
"product":"Product2",
"feature":[
"Feature1",
"Feature2"
]
}, {
"product":"Product3",
"feature":[
"Feature1",
"Feature2",
"Feature3",
"Feature4"
]
}, {
...
}
]
I use ADOMD.NET library using ExecuteCellSet(), but I'm also new to this one as well. Can someone point me to the right direction?
Thanks,
dfox
Although I am not familiar with MDX, I have used JSON in C#. One way to create a JSON object (since they are not native in C# as of 4.5) is by using DataContracts.
using System.Runtime.Serialization.Json;
using System.Runtime.Serialization;
namespace Interface.Data
{
[DataContract]
class jsonObject
{
[DataMember]
public String product="";
[DataMember]
public String[] feature={"", "", ""};
public jsonObject(){}
}
}
Then in your MDX query, assuming you are storing the query data in some string 'line', you can do:
using System.Runtime.Serialization.Json;
using System.Data.Common;
using System.IO;
static jsonObject json;
public static MDXObj parseMDXObj(String line)
{
MDXObj obj = new MDXObj(getMDX());
try
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(jsonObject));
MemoryStream stream = new MemoryStream(ASCIIEncoding.UTF8.GetBytes(line));
json = (jsonObject)ser.ReadObject(stream);
}
catch (Exception e)
{
Console.WriteLine("Error Occurred in creating JSON: " + e.Message);
return null;
}
return obj;
}
Related
I'm trying to make a todo application on Spring. It's almost finished but I got a problem. I need to filter todos by user id and select them which is in the between given dates. I've created a method for this in my TodoRepository. But when I send the request to the url, it gives me empty array.
Here's the repository class:
All methods work fine except the one I mentioned btw.
#Repository
public interface TodoRepository extends JpaRepository<Todo, Long> {
List<Todo> findTodosByUserId(Long id);
List<Todo> findTodosByUserIdOrderByDateAsc(String id);
List<Todo> findAllByDateBetween(Date date, Date date2);
List<Todo> findTodosByDateBetweenAndUserId(Date date, Date date2, Long id);
}
That's the method i use in the TodoService class:
#Service
public class TodosService {
#Autowired
TodoRepository todoRepository;
//other methods..
public List<Todo> filterTodosByUserId(FilterTodoByUserDto dto){
Date date1 = dto.getDate1();
Date date2 = dto.getDate2();
Long id = dto.getId();
return todoRepository.findTodosByDateBetweenAndUserId(date1, date2, id);
}
}
FilterTodoByUserDto class:
public class FilterTodoByUserDto {
private Long id;
private Date date1;
private Date date2;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Date getDate1() {
return date1;
}
public void setDate1(Date date1) {
this.date1 = date1;
}
public Date getDate2() {
return date2;
}
public void setDate2(Date date2) {
this.date2 = date2;
}
#Override
public String toString() {
return "FilterTodoByUserDto{" +
"id=" + id +
", date1=" + date1 +
", date2=" + date2 +
'}';
}
}
And lastly, controller class:
#RestController
#RequestMapping("/api")
public class TodoController {
#Autowired
private TodosService todosService;
//other methods..
#GetMapping("user/todos/filter")
public List<Todo> filterTodosById(#RequestBody FilterTodoByUserDto dto){
List<Todo> todos = todosService.filterTodosByUserId(dto);
return todos;
}
//other methods..
}
Request body that i sent with postman:
{"userId":"1", "date1":"2021-01-01", "date2":"2000-01-01"}
Database output:
mysql> select * from todos;
+----+----------------------------+-------------+-------------+---------+
| id | date | description | todo_status | user_id |
+----+----------------------------+-------------+-------------+---------+
| 1 | 2012-12-12 00:00:00.000000 | deneme | TODO | 2 |
| 2 | 2010-10-10 00:00:00.000000 | deneme2 | TODO | 2 |
| 3 | 2010-01-01 00:00:00.000000 | deneme5 | DONE | 1 |
| 4 | 2010-01-01 00:00:00.000000 | deneme | DONE | 1 |
| 5 | 2010-01-01 00:00:00.000000 | deneme | DONE | 1 |
| 6 | 2010-01-01 00:00:00.000000 | deneme | DONE | 1 |
| 7 | 2010-01-01 00:00:00.000000 | deneme | DONE | 1 |
| 8 | 2010-01-01 00:00:00.000000 | deneme | DONE | 1 |
| 9 | 2010-01-01 00:00:00.000000 | deneme | DONE | 2 |
+----+----------------------------+-------------+-------------+---------+
9 rows in set (0,01 sec)
Change your request json like this:
{
"id": "1",
"date1": "2000-01-01",
"date2": "2021-01-01"
}
Your fields in your DTO model should match your json fields. (userId -> id)
BETWEEN returns true if the value of date is greater than or equal to the value of begin_expression and less than or equal to the value of end_expression. (.. date BETWEEN date1 AND date2)
You are getting empty array due to your postman request is logically wrong. When BETWEEN use date1 must be the minimum value and date2 must be the maximum value.
ex: The following date example uses the BETWEEN condition to retrieve values within a date range.
SELECT *
FROM todos
where user_id=1
and date between '2000-01-01' and '2021-01-01';
Above BETWEEN SQL would be equivalent to the following SELECT statement:
SELECT *
FROM todos
where user_id=1
and date >= '2000-01-01' and date<= '2021-01-01';
Here is my abstract class :
package mypackage.commons
abstract class Content {
String name
static constraints = {
name nullable: false, blank: false, size: 1..50
}
}
Here is my class which is extended :
package mypackage.project
import mypackage.commons.Content
class Plane extends Content {
String something;
}
Here is my Bootstrap.groovy file :
package mypackage
import mypackage.commons.Content
import mypackage.project.Plane
class BootStrap {
def init = { servletContext ->
Plane boing1 = new Plane (name: 'Boing', something: 'Hello').save()
Plane boing2 = new Plane (name: 'Boing', something: 'Goodbye').save()
}
def destroy = {
}
}
The problem is when I go on MySQL, when I use SHOW TABLES, I only can see content plane.
Here is the content of SELECT * FROM content;
+----+---------+-------+-------------------------+-----------+
| id | version | name | class | something |
+----+---------+-------+-------------------------+-----------+
| 1 | 0 | Boing | mypackage.project.Plane | Hello |
| 2 | 0 | Boing | mypackage.project.Plane | Goodbye |
+----+---------+-------+-------------------------+-----------+
EDIT
After testing Mike's answer :
package mypackage.commons
abstract class Content {
String name
static constraints = {
name nullable: false, blank: false, size: 1..50
}
static mapping = {
tablePerHierarchy false
}
}
here is the result of SHOW TABLES
+-----------------------+
| Tables_in_my_database |
+-----------------------+
| content |
| plane |
+-----------------------+
Here is the result of SELECT * FROM content :
+----+---------+-------+
| id | version | name |
+----+---------+-------+
| 1 | 0 | Boing |
| 2 | 0 | Boing |
+----+---------+-------+
Here is the result of SELECT * FROM plane :
+----+------------+
| id | something |
+----+------------+
| 1 | Hello |
| 2 | Goodbye |
+----+------------+
END OF EDIT
Expected behaviour :
SHOW TABLES; should show me only the table plane
SELECT * FROM plane should show me this :
+----+---------+-------+------------+
| id | version | name | something |
+----+---------+-------+------------+
| 1 | 0 | Boing | Hello |
| 2 | 0 | Boing | Goodbye |
+----+---------+-------+------------+
How can I obtain the expected result ?
Is it possible ?
Thanks in advance.
You need to tell Grails to use table-per-subclass strategy by telling it not to use table-per-hierarchy like:
package mypackage.commons
abstract class Content {
String name
static constraints = {
name nullable: false, blank: false, size: 1..50
}
static mapping = {
tablePerHierarchy false
}
}
I found an answer, I wonder if it's the best way, but it works.
This topic helps me : https://github.com/grails/grails-data-mapping/issues/1254
Firstly, I understand that if I don't want a class to be mapped by Grails, I have to put this class outside of "Domain" package.
So I moove my Content class into src -> main -> groovy -> common (I created this folder) -> Content.groovy
Here is my Content class :
package common
abstract class Content {
String name
static constraints = {
name nullable: false, blank: false, size: 1..50
}
}
Here is my Plane class :
package mypackage.project
import common.Content
class Plane extends Content {
String something;
}
And here is my Bootstrap.groovy :
package mypackage
import mypackage.project.Plane
class BootStrap {
def init = { servletContext ->
Plane boing1 = new Plane (name: 'Boing', something: 'Hello').save()
Plane boing2 = new Plane (name: 'Boing', something: 'Goodbye').save()
}
def destroy = {
}
}
So I avoid tablePerHierarchy use.
In the topic, thay talked about #MappedSupperclass, I don't know what it refers to. I did not use it.
Expected behaviour is reach.
Is it the correct way to do it ?
I would like to create a json out of 2 dataframes (one is Parent and the other is child). Child records should be an array forming a nested JSON
Df1 (Department):
+----------+------------+
| dept_Id | dept_name |
+----------+------------+
| 10 | Sales |
+----------+------------+
Df2 (Employee):
+----------+--------+----------+
| dept_Id | emp_id | emp_name |
+----------+--------+----------+
| 10 | 1001 | John |
| 10 | 1002 | Rich |
+----------+--------+----------+
I want the JSON to be created as follows:
{
"dept_id":"10",
"dept_name":"Sales",
"employee":[
{ "emp_id":"1001","emp_name":"John" },
{ "emp_id":"1002","emp_name":"Rich" }
]
}
Appreciate your thoughts. Thanks
First join the two dataframes together:
val df = df1.join(df2, Seq("dept_Id"))
Then use groupBy and collect_list. Two case classes is used here to get the correct names in the final json. These should be placed outside of the main method.
case class Department(dept_Id: Int, dept_name: String, employee: Seq[Employee])
case class Employee(emp_id: Int, emp_name: String)
val dfDept = df.groupBy("dept_id", "dept_name")
.agg(collect_list(struct($"emp_id", $"emp_name")).as("employee"))
.as[Department]
Resulting dataframe:
+-------+---------+--------------------------+
|dept_id|dept_name|employee |
+-------+---------+--------------------------+
|10 |Sales |[[1002,Rich], [1001,John]]|
+-------+---------+--------------------------+
Finally, save it as a json file:
dfDept .coalesce(1).write.json("department.json")
Items Table
| id | item_id | item_title |
|-------|---------|------------|
| 1 | 1002 | A |
| 2 | 1003 | B |
| 3 | 1004 | C |
Sells Table
| id | item_id |
|----|-----------|
| 1 | 1002 1003 |
| 2 | 1003 1004 |
| 3 | 1004 1002 |
I want result : Sells Table 1. item title is A B
I want to combine the sells table with the item table and then match the item_id of the sells table to the item_title of the item table.
The table definitions look incorrect, you should have a pivot table linking items with sells, so a sell_item table:
item_id | sell_id
-----------------
1 | 1
1 | 3
2 | 1
2 | 2
3 | 2
3 | 3
Then using eloquent, you'd create models to represent your tables and define the relationships using BelongsToMany:
class Item extends Model {
public function sells() {
return $this->belongsToMany(Sell::class);
}
}
class Sell extends Model {
public function items() {
return $this->belongsToMany(Item::class);
}
}
Each instance of either model will then have access to it's related models via $item->sells and $sell->items.
The query builder can perform a join if not going the Eloquent route:
DB::table('sells')->join('items', 'sells.item_id', '=', 'items.item_id')
->select('sells.*', 'items.title')
->get();
The table definitions look incorrect, If you corrected already then your model replationship should be like
class Item extends Model {
public function sells() {
return $this->belongsToMany(Sell::class);
}
}
class Sell extends Model {
public function items() {
return $this->belongsToMany(Item::class);
}
}
Each instance of either model will then have access to it's related models via $item->sells and $sell->items.
The query builder can perform a join if not going the Eloquent route:
DB::table('sells')->join('items', 'sells.item_id', '=', 'items.item_id')
->select('sells.*', 'items.title')
->get();
Or if your model name is Sell then
$response=Sell::with('items')->get();
My Controller Class:
public function postAction(Request $request)
{
$content = $request->getContent();
$category = $this->get('jms_serializer')->deserialize($content,'AppBundle\Entity\Category','json');
$errors = $this->get('validator')->validate($category);
if (count($errors) > 0) {
return new View("NAME LENGTH MUST BE >4",Response::HTTP_BAD_REQUEST);
} else {
$em = $this->getDoctrine()->getManager();
$em->persist($category);
$em->flush();
return new View($category, Response::HTTP_OK);
}
}
Entity:
class Category
{
private $id;
private $parent;
public function getChildren()
{
return $this->children;
}
private $children;
public function __construct()
{
$this->children = new ArrayCollection();
}
//setters and getters
Doctrine.yml:
AppBundle\Entity\Category:
type: entity
oneToMany:
children:
targetEntity: AppBundle\Entity\Category
mappedBy: parent
orderBy:
name: ASC
manyToOne:
parent:
targetEntity: AppBundle\Entity\Category
inversedBy: children
joinColumn:
name: parentId
referencedColumn: id
table: category
repositoryClass: AppBundle\Repository\CategoryRepository
id:
id:
column: id
type: integer
id: true
generator:
strategy: AUTO
fields:
name:
type: string
lenght: 255
When I send POST json request like this:
{
"name": "Child to 8",
"parentId": "8"
}
In MySQL table i do not recieve parentId:
mysql> select * from category;
+----+--------------------+----------+
| id | name | parentId |
+----+--------------------+----------+
| 1 | Primary Category | NULL |
| 2 | Secondary Category | 1 |
| 3 | D_child | 1 |
| 4 | F_child | 1 |
| 5 | Z_child | 1 |
| 6 | Y_child | 1 |
| 7 | H_child | 1 |
| 8 | A_child | 1 |
| 9 | Child to 8 | NULL |<----- must be 8
+----+--------------------+----------+
But after deserialization i receive this:
{
"id": 9,
"name": "Child to 8"
}
I understand that id is an integer, but parentId is already an object of class Category. But how to make it so that he also signed up?
How can i do this? Maybe I do not understand something ...
You need to have a .yml config file for serializer. In your case - Entity.Category.yml.
In this file add property of nested entities, set him a type of you Entity and for be sure accessors (setter, getter).