Objection insertGraph, insert new and relate or relate to existing rows - javascript

So, I'm not super knowledge with MySQL relations, upserting and such. I'm looking for an explanation on how (if?) this is possible to do.
[
{
scheduledAt: '17:55',
league: { name: 'Champions League - Group Stage' }
},
{
scheduled_at: '19:45',
league: { name: 'Champions League - Group Stage' }
},
{
scheduled_at: '19:30',
league: { name: 'Primera B Metropolitana' },
},
{
scheduled_at: '21:00',
league: { name: 'Primera B Metropolitana' }
}
]
Say I wanted to insert this graph of data. The root objects are going into the fixtures table, and the league property is this relation in the Fixtures model.
{
league: {
relation: Model.BelongsToOneRelation,
modelClass: `${__dirname}/League`,
join: {
from: 'fixtures.league_id',
to: 'leagues.id'
}
}
}
So, currently if I use insertGraph to insert all this data. It's inserts into both the fixtures and leagues table and relates as you would expect.
{
"scheduled_at": "17:55",
"league": {
"name": "Champions League - Group Stage",
"created_at": "2018-10-03T13:02:03.995Z",
"id": 1
},
"league_id": 1
"created_at": "2018-10-03T13:02:04.042Z",
"id": 1
}
However if I insert the exact same league object, it will just create another duplicate league and fixture row with the next incremented ID (2 in this case).
Is it possible for it to find if a league exists with that name, and then use that row/ID as the league_id, like so:
{
"scheduled_at": "17.55",
"league_id": 1
"created_at": "2018-10-03T13:02:04.042Z",
"id": 2
}
Sorry if I've explained this horrendously. But I'm not so hot on the terminology so I don't know what I'm actually looking to do. I feel like this is a super easy thing, but maybe my structure or method is wrong.

Related

When should I use the read/writeQuery and when the read/writeFragment while working with the Apollo Cache?

I'm working with the Apollo local cache and I found that the read/writeQuery works in the same way as read/writeFragment. Both of them do the same thing and the only difference at my opinion is just that the readQuery returns an object that contains the query name as a key and the query result as a value. The readFragment returns the query result object itself.
Based on the official documentation about readQuery I could assume that it executes the query and returns the data.
About the readFragment things look the same. The only difference is that in the case of Fragment I should pass the composed ID of the required item that Apollo cache uses itself.
But the result is totally the same as in the case of readQuery except that it returns the object of values.
Here is the code example.
Sorry, there are will be a lot of cumbersome boilerplate. Simple but a lot to demonstrate the problem in very detail.
The schema of the Track (I'll omit other types to reduce the code boilerplate):
type Track {
id: ID!
title: String!
author: Author!
thumbnail: String
length: Int
modulesCount: Int
description: String
numberOfViews: Int
modules: [Module!]!
}
The readQuery example with the all the Track fields:
const { track } = client.readQuery({
query: gql`
query getTrack($trackId: ID!) {
track(id: $trackId) {
id
title
author {
id
name
photo
}
thumbnail
length
modulesCount
numberOfViews
modules {
id
title
length
}
description
}
}
`,
variables: {
trackId: 'c_1',
},
});
The result is:
{
"__typename": "Track",
"id": "c_1",
"title": "FAMOUS CATSTRONAUTS",
"author": {
"__typename": "Author",
"id": "cat-2",
"name": "Grumpy Cat",
"photo": "https://images.unsplash.com/photo-1593627010886-d34828365da7?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjExNzA0OH0"
},
"thumbnail": "https://res.cloudinary.com/dety84pbu/image/upload/v1598474100/famous_cats_epuqcr.jpg",
"length": 1916,
"modulesCount": 5,
"numberOfViews": 26,
"modules": [
{
"__typename": "Module",
"id": "l_10",
"title": "Neil Armstrong",
"length": 321
},
{
"__typename": "Module",
"id": "l_11",
"title": "Yuri Gagarin",
"length": 470
},
{
"__typename": "Module",
"id": "l_12",
"title": "Buzz Aldrin",
"length": 545
},
{
"__typename": "Module",
"id": "l_13",
"title": "John Glenn",
"length": 357
},
{
"__typename": "Module",
"id": "l_14",
"title": "Chris Hadfield",
"length": 223
}
],
"description": "Be inspired by famous catstronauts who have made their names legend from across the galaxies. Special guest appearance included, so hold on to your boots!"
}
Now the readFragment example (all fields):
const track = client.readFragment({
id: 'Track:c_1',
fragment: gql`
fragment MyTrack on Track {
id
title
author {
id
name
photo
}
thumbnail
length
modulesCount
numberOfViews
modules {
id
title
length
}
description
}
`
});
The result is the same as in the case of the readyQuery.
Now the example with the partial fields.
For the readQuery:
const { track } = client.readQuery({
query: gql`
query getTrack($trackId: ID!) {
track(id: $trackId) {
id
title
}
}
`,
variables: { // Provide any required variables here. Variables of mismatched types will return `null`.
trackId: 'c_1',
},
});
The result will be:
{
"__typename": "Track",
"id": "c_1",
"title": "FAMOUS CATSTRONAUTS"
}
The readFragment (partial fields)
const track = client.readFragment({
id: 'Track:c_1',
fragment: gql`
fragment MyTrack on Track {
id
title
}
`
});
The result will be the same as readyQuery!
My question: When should I use the readQuery and when the readFragment? It looks like they provide the same result.
The same for writeQuery and the writeFragment. They do the same at the first look.
writeQuery partial update code example:
client.writeQuery({
query: gql`
query WriteTrack($trackId: ID!) {
track(id: $trackId) {
id
title
},
}`,
data: { // Contains the data to write
track: {
__typename: 'Track',
id: 'c_1',
title: 'Buy grapes 🍇',
},
},
variables: {
id: 'c_1'
}
})
writeFragment partial update code example:
client.writeFragment({
id: 'Track:c_1',
fragment: gql`
fragment MyTrack on Track {
id
title
}
`,
data: {
__typename: 'Track',
id: 'c_1',
title: 'Buy grapes 🍇',
}
})
The result is the same. Both update the title. So what is the difference? When should I use the writeQuery and when the writeFragment?
Thanks for any help and your patience and time!

Retreiving specific data from JSON repsonse only in certain array indexes

Hey sorry if this has been asked before, I haven't found an answer that has helped me.
I am working on building a personal application using the free Ticketmaster application but I'm having trouble with the JSON response.
An example of the response is:
data: {
classifications: [
type: {
id: 1,
name: "Dont want this"
}
],
[
type: {
id: 2,
name: "Dont want this"
}
],
[
category: {
id: 3,
name: "Food & Drink"
}
],
[
category: {
id: 4,
name: "Music"
]
}
I am trying to retrieve category names such as "Family", "Food & Drink", "Music" etc but only at some indexes does the array have category objects, the others have type.
Can someone tell me how to go through this array and only get the name when it is at category.name?
Any help is appreciated :)

$lookup search Mongodb

Objective
To have an efficient search using references in MongoDB.
Background
I have a Smoothie DB on Mongo. A smoothie is an object with a reference to a Food object and it is represented like:
{
name: "Red Velvet Cake",
ingredients: [{
food_id: "strawberry_raw",
//other really cool fields
},
//other ingredients
],
preparation: "Mix everything and have fun!",
Source: "Super Smoothies, p. 142"
}
Now, a Food object is represented by the following example:
{
"_id": "strawberry_raw",
"name": "strawberries",
//other really cool fields
}
Problem
With these schemas in mind, I am making sure that a Smoothie object knows all the Food objects that build it. Since each Smoothie object will have at most 6 or 7 food objects, I believe this is the best choice as it follows the MongoDB's Principle of least Cardinality.
However, now I want to allow the following functionalities:
Given a list of ingredient names, return all smoothies that contain at least one of those ingredients
Given a list of ingredient names, return only the smoothies that contain all those ingredients.
And I have no idea how to do it with MongdoDB.
Example
The following examples illustrate what I want.
Imagine I have the following Foods:
let foods = [{
"_id": "strawberry_raw",
"name": "strawberries"
}, {
"_id": "honeydew_melon_raw",
"name": "honeydew melon"
}, {
"_id": "coconut_milk",
"name": "homemade coconut milk"
}];
And the following Smoothies:
let smoothies = [
{
name: "Coco Berry",
ingredients: [
{ food_id: "strawberry_raw" },
{ food_id: "coconut_milk"}
],
preparation: "Mix everything and have fun!",
Source: "Super Smoothies, p. 142"
},
{
name: "Tropical Melon",
ingredients: [
{ food_id: "honeydew_melon_raw"},
{ food_id: "coconut_milk"}
],
preparation: "Mix everything and have fun!",
Source: "Super Smoothies, p. 51"
}];
Given a search with the term "coconuts, strawberry", the functionalities would return:
Coco Berry and Tropical Melon, as both smoothie have at least one of the ingredients (coconut milk)
Coco Berry, as this smoothie has both ingredients, and the second one is missing one ingredient.
What I tried and what i need
I know that to turn a search like "coconuts" return a Food with name "Coconut Milk" I have to index the names in the Food collection, which I did.
I also searched and I found that I will likely need to use $lookup, however, I don't know how to move from that point forward. How do I do it ?
I think there is no need of adding a join or index you can use $regex,let me try my hand,consider smothie as your collection
`
db.collection.find({ingredients : {$elemMatch : {$or :[
{food_id : {$regex : "coconuts")},{food_id : {$regex : "strawberry")}]}}})
`
Your second query
`
db.collection.find({ingredients : {$elemMatch : {$and :[
{food_id : {$regex : "coconuts")},{food_id : {$regex : "strawberry")}]}}})
`

Having trouble wrapping my head around complex $group'ing/aggregation

I have a schema that is something like this:
{
_id: <objectid>
customer: <objectid>
employee: <objectid>
date: <Month/day/year>
amount: <Number>
}
Using angular, I'm trying to make a page that pulls that data and builds separate tables for each day. So something like I would have a tab for yesterday, that would open up a view for a table that has all of my employees listed and the sum of their for the day. Something like this:
[{
date: 10/29/2019
dataFromThisDate: [
{
employee: <name>
sumAmount: <sum(amount for this date)>
list: [<array of all of the transaction _ids
},
{
employee: <name 2>
//etc
}]
},
{
date: 10/30/2019
dataFromThisDate: //etc
}]
Basically as far as I've gotten is just:
MyCollection.aggregate(
[{
$group: {
_id: "$date"
}
}],function(err, result) { //blah }
)
But I'm not sure how to even do nested grouping (first by date, then by employee on that date). Just thinking through it, it feels like I would have to group by date, then pass on all the data to a new grouping pipeline?
Sorry I don't have more of what I've tried, this whole aggregation thing is just completely new to me and I can't find good examples that are similar enough to what I'm trying to do to learn from. I looked at the api docs for mongodb and I understand their basic examples and play around with them, but I'm just having a hard time coming up with how to do my more complex example.
You can try something like this. This uses two groups. First group by date and employee, summing the amount and adding the transaction ids. Second group by date and add the employees with their total amount and transactions list.
aggregate([{
$group: {
_id: {
date: "$date",
employee: "$employee"
},
amount: {
$sum: "$amount"
},
transactionIds: {
$push: "$_id"
}
}
}, {
$group: {
_id: "$_id.date",
dataFromThisDate: {
$push: {
employee: "$_id.employee",
sumAmount: "$amount",
list: "$transactionIds"
}
}
}
}])
Output
{
"_id": "12/21/2016",
"dataFromThisDate": [{
"employee": "employee1",
"sumAmount": 100,
"list": [ObjectId("58151e881ac3c9ce82782663")]
}, {
"employee": "employee2",
"sumAmount": 73,
"list": [ObjectId("58151e881ac3c9ce82782665"), ObjectId("58151e881ac3c9ce82782666")]
}]
}

How do I properly map attributes of relations in sequelize.js?

I'm creating a recipe-database (commonly known as a cookbook) where I need to have a many-to-many relationship between ingredients and recipes and I'm using sequelize.js in combination with postgresql.
When an ingredient is added to a recipe I need to declare the correct amount of that ingredient that goes into the recipe.
I've declared (reduced example)
var Ingredient = sequelize.define('Ingredient', {
name: Sequelize.STRING
}, {
freezeTable: true
});
var Recipe = sequelize.define('Recipe', {
name: Sequelize.STRING
}, {
freezeTable: true
});
var RecipeIngredient = sequelize.define('RecipeIngredient', {
amount: Sequelize.DOUBLE
});
Ingredient.belongsToMany(Recipe, { through: RecipeIngredient });
Recipe.belongsToMany(Ingredient, {
through: RecipeIngredient,
as: 'ingredients'
});
My problem is with how data is returned when one my REST endpoints do
router.get('/recipes', function(req, res) {
Recipe.findAll({
include: [{
model: Ingredient,
as: 'ingredients'
}]
}).then(function(r) {
return res.status(200).json(r[0].toJSON());
})
});
The resulting JSON that gets sent to the client looks like this (timestamps omitted):
{
"id": 1,
"name": "Carrots",
"ingredients": [
{
"id": 1,
"name": "carrot",
"RecipeIngredient": {
"amount": 12,
"RecipeId": 1,
"IngredientId": 1
}
}
]
}
While all I wanted was
{
"id": 1,
"name": "Carrots",
"ingredients": [
{
"id": 1,
"name": "carrot",
"amount": 12,
}
]
}
That is, I want the amount field from the relation-table to be included in the result instead of the entire RecipeIngredient object.
The database generated by sequelize looks like this:
Ingredients
id name
1 carrot
Recipes
id name
1 Carrots
RecipeIngredients
amount RecipeId IngredientId
12 1 1
I've tried to provide an attributes array as a property to the include like this:
include: [{
model: Ingredient,
as: 'ingredients',
attributes: []
}]
But setting either ['amount'] or ['RecipeIngredient.amount'] as the attributes-value throws errors like
Unhandled rejection SequelizeDatabaseError: column ingredients.RecipeIngredient.amount does not exist
Obviously I can fix this in JS using .map but surely there must be a way to make sequelize do the work for me?
I am way late to this one, but i see it been viewed quite a bit so here is my answer on how to merge
attributes
Some random examples in this one
router.get('/recipes', function(req, res) {
Recipe.findAll({
include: [{
model: Ingredient,
as: 'ingredients',
through: {
attributes: ['amount']
}
}]
})
.then(docs =>{
const response = {
Deal: docs.map(doc =>{
return{
cakeRecipe:doc.recipe1,
CokkieRecipe:doc.recipe2,
Apples:doc.ingredients.recipe1ingredient
spices:[
{
sugar:doc.ingredients.spice1,
salt:doc.ingredients.spice2
}
]
}
})
}
})
res.status(200).json(response)
})
You can use sequelize.literal. Using Ingredient alias of Recipe, you can write as follows. I do not know if this is the right way. :)
[sequelize.literal('`TheAlias->RecipeIngredient`.amount'), 'amount'],
I tested with sqlite3. Received result with alias "ir" is
{ id: 1,
name: 'Carrots',
created_at: 2018-03-18T04:00:54.478Z,
updated_at: 2018-03-18T04:00:54.478Z,
ir: [ { amount: 10, RecipeIngredient: [Object] } ] }
See the full code here.
https://github.com/eseom/sequelize-cookbook
I've gone over the documentation but I couldn't find anything that seems like it would let me merge the attributes of the join-table into the result so it looks like I'm stuck with doing something like this:
router.get('/recipes', function(req, res) {
Recipe.findAll({
include: [{
model: Ingredient,
as: 'ingredients',
through: {
attributes: ['amount']
}
}]
}).then(function(recipes) {
return recipes[0].toJSON();
}).then(function(recipe) {
recipe.ingredients = recipe.ingredients.map(function(i) {
i.amount = i.RecipeIngredient.amount;
delete i.RecipeIngredient;
return i;
});
return recipe;
}).then(function(recipe) {
return res.status(200).json(recipe);
});
});
Passing through to include lets me filter out which attributes I want to include from the join-table but for the life of me I could not find a way to make sequelize merge it for me.
The above code will return the output I wanted but with the added overhead of looping over the list of ingredients which is not quite what I wanted but unless someone comes up with a better solution I can't see another way of doing this.

Categories