Select from MySQL WHERE IN [values array] - javascript

I need to make a select from MySQL with the selection values in an array. I have data like this:
const CompaniesRelation = [{CompanyId: ""},{CompanyId: ""},{CompanyId: ""},{CompanyId: ""},{CompanyId: ""}];
With Companies Relation I need to select/find, I need to get all the information for each CompanyId's:
const Companies: Array<Company> = await getRepository(Company).find({ where:{ CompanyId: CompaniesRelation[0].CompanyId, IsActive: true} });
I'm using TypeOrm in Angular. I need to select the information for each object into CompaniesRelation. I need to use fewest selects to DB, in other words, foreach is not the way.
For the final result I need to have an array with all the information of each company in Companies Relation, like this:
[{CompanyId: "", Name: "", fk:""},{CompanyId: "", Name: "", fk:""},{CompanyId: "", Name: "", fk:""}]

How you use WHERE x IN explained in find options for find*, and adding WHERE expression for QueryBuilder.
First get your Company Ids into an array of integers:
const companyIds = [1, 2, 3];
or
const companySel = [{ CompanyId: 1 }, { CompanyId: 2 }, { CompanyId: 3 }];
const companyIds = companySel.map(a => a.CompanyId);
Then you can use the In operator with find
import {In} from "typeorm";
const companyList = await getRepository(Company)
.find({ where: { CompanyId: In (companyIds ) } });
Or you can use the TypeOrm QueryBuilder with "IN" (note the :... syntax)
const companyList = await getRepository(Company)
.createQueryBuilder()
.where("CompanyId IN (:...ids )", { ids: companyIds ) })
.getMany();

Related

How can I add keys in the array, and generate input fields with them?

The user has the possibility to enter his name. I get the name in a array. Example: ["Dilan", "Chris", "Robert"]
So what I'm trying to do is to get the name from the user, but also another value inside the array.
Example:
initialName = {
name: "",
active: "",
};
Also, I need the initalName to be inside an array.
This is what I have tried by far
const initialName = {
name: "",
active: ""
};
export default function AddingNames() {
const [names, setNames] = useState([initialName ]);
const handleAddClick = () => {
setLanguages([...names, initialName]);
};
const handleItemChanged = (event, index) => {
const value = event.target.value;
const list = [...initialName];
list[index] = value;
setNames(list);
console.log(names);
};
And this error is showed: TypeError initialName is not iterable
What I want to get from the user its just the name value in the initialName.
How can I make it work?
you can only use ... in case of iterable variable, in this case initialName is not iterable since its object
I suppose you are trying to achieve array that looks something like this:
list =
[
{name: "boo", active: "foo"},
{name: "john", active: "doe"}
]
In this case what you could do is
list[index] = {name: value, active: ""};
setNames(list)
So initial name is not iterable here as you are trying to do in usestate([]) because initial name is an object not an array. If you had an array say:
let users = [{
name: "",
active: "",
}]
Then you could iterate over the users array and access the name of a user by
let variable = user[0].name

Trying to iterate through an object's values and insert into new object (JS)

I am trying to create a series of new objects using the values from an existing object to push to my database.
Here is the existing object:
{
name: 'Pasta',
method: 'Cook pasta',
ingredients: [
{ measure: 'tbsp', quantity: '1', ingredient_name: 'lemon' },
{ measure: 'g', quantity: '1', ingredient_name: 'salt' },
{ measure: 'packet', quantity: '1', ingredient_name: 'spaghetti' },
{ measure: 'litre', quantity: '1', ingredient_name: 'water' }
]
}
Basically I have a function that inserts and returns the id of the recipe into one table, then inserts and returns/or finds the ids of the relevant ingredients and the final part (with which I am struggling) is to combine the returned recipe_id, ingredient_id and the correct measure and quantity (as written in the object above).
Here is where I have gotten to:
//starting point is here
async function addNewRecipe(newRecipe, db = connection) {
console.log(newRecipe)
const recipeDetails = {
recipe_name: newRecipe.name,
recipe_method: newRecipe.method,
}
const ingredientsArray = newRecipe.ingredients
const [{ id: recipeId }] = await db('recipes')
.insert(recipeDetails)
.returning('id')
const ingredientsWithIds = await getIngredients(ingredientsArray) //returns an array of ids
ingredientsWithIds.forEach((ingredientId) => {
let ingredientRecipeObj = {
recipe_id: recipeId, //works
ingredient_id: ingredientId, //works
measure: newRecipe.ingredients.measure, //not working - not sure how to match it with the relevant property in the newRecipe object above.
quantity: newRecipe.ingredients.quantity,//not working - not sure how to match it with the relevant property in the newRecipe object above.
}
//this is where the db insertion will occur
})
}
The desired output would be:
ingredientRecipeObj = {
recipe_id: 1
ingredient_id: 1
measure: tbsp
quantity: 1
} then insert this into db
followed by:
ingredientRecipeObj = {
recipe_id: 1
ingredient_id: 2
measure: g
quantity: 1
} then insert into db
etc. etc.
The problem seems to be that the function "getIngredients" returns only the IDs. Once you have fetched them, you have no way of knowing which ID is for which ingredient. One way to change that is to make the method return an array of both the ID and the ingredient name. Then you could match them like this:
const ingredientsWithIds = await getIngredients(ingredientsArray) //now an array of objects with ingredient_name and id
ingredientsWithIds.forEach((ingredient) => {
const recipeIngredient = ingredientsArray.find(ri => ri.ingredient_name === ingredient.ingredient_name)
const ingredientRecipeObj = {
recipe_id: recipeId,
ingredient_id: ingredient.id,
measure: recipeIngredient.measure,
quantity: recipeIngredient.quantity,
}
//this is where the db insertion will occur
})
Since you haven't posted the "getIngredients" function it is hard to say exactly how to adapt it to return the name as well.

Using findById to find the id of a schema in an array

Hey I was wondering how do I use findById for a schema inside an array? For example, I have the following Schema:
const GameSchema = new mongoose.Schema({
users: [
{
user: { type: mongoose.Schema.ObjectId, ref: 'User' },
role: {
type: String,
required: true,
enum: ['user', 'moderator', 'creator'],
default: 'user',
},
},
]
}]
I want to find the user with a mongoose function like findById, such as the following:
const user = await game.users.findById({ user: req.user.id })
It doesn't seem to work since users is not a mongodb model. I know I can find the user by using find() like the following:
const user = await game.users.find(
(gameUser) => gameUser.user == req.user.id
)
The only problem is that the type of gameUser and req.user.id is not the same and I can't use '==='. Is there some way to go through the array and use the mongoose function findById?
As docs explains, findById method:
Finds a single document by its _id field
So you have to use findOne() instead of findById().
Also, to return only one field from the entire array you can use projection into find.
Check this example. This query find an object by its id (i.e. user field) and return only the object, not the whole array.
db.collection.find({
"users": { "$elemMatch": { "user": 1 } }
},
{
"users.$": 1
})
Using mongoose you can do:
yourModel.findOne(({
"users": { "$elemMatch": { "user": 1 } }
},
{
"users.$": 1
})).then(result => {
console.log(result)
}).catch(e => {
// error
})

How to update only one property in MongoDB using Mongoose?

This is my model:
import mongoose from 'mongoose';
const UserData = new mongoose.Schema({
additionalData: Array,
name: String,
});
mongoose.model('UserData', UserDataSchema);
mongoose.set('useFindAndModify', false);
export default mongoose.model('UserData');
How can I update additionalData property of UserData model so for example another array is appended.
Let's say additional array is
[ 1, 2, 3]
You can use $addToSet
await UserData.update({name:"something"},{ $addToSet: { additionalData: [1,2,3] })
or
await UserData.updateOne({name:"something"},{ $addToSet: { additionalData: [1,2,3] })
If you have no condition do this ,this will add to all documents
await UserData.update({},{ $addToSet: { additionalData: [1,2,3] })
If you want to remove multiple values from the array,use $pull
await UserData.update({},{ $pull: { additionalData: { $in: [ 1, 2,3 ] }}})
If you wish to remove single value
await UserData.update({},{ $pull: { additionalData:1 }})
If this is not what you mean, let me know in the comments, I'll edit the answer.
const newArray = [ 1, 2, 3];
const nameToUpdate = 'foo';
mongoose.model('UserData').updateMany({
name: nameToUpdate
}, {$set: {
additionalData: newArray
}});

How does group by works in sequelize?

I am looking for group by queries through Sequelize and cannot seem to find any documentation.
SELECT column, count(column)
FROM table
GROUP BY column
issue: https://github.com/sequelize/sequelize/issues/348
User.findAll({
group: ['field']
})
i use sequelize#2.0.0-dev9
I think you looking for something like this:
Table.findAll({
attributes: ['column1',
sequelize.fn('count', sequelize.col('column2'))],
group: ["Table.column1"]
}).success(function (result) { });
Update: Newer versions of Sequelize uses .then instead of .success.
Table.findAll({
attributes: ['column1',
sequelize.fn('count', sequelize.col('column2'))],
group: ["Table.column1"]
}).then(function (result) { });
Group by with count sequelize ORM
'field' - custom user input, you can rename this string, it's your field(column) in database
'count' - reserved sequelize keyword string need for get count in sequelize
'cnt' - custom user input, you can rename this string, it's your output count
Sequelize version 3.25.0
User.findAll({
attributes: ['field', [sequelize.fn('count', sequelize.col('field')), 'cnt']],
group: ['field'],
})
Try this -
Table.count(
{
attributes: ['column'],
group: 'column',
}
Example: how to add an convenient alias to the grouped function column.
I did this as a separate response mostly because it wouldn't format well in a comment... otherwise I would have just added it to Sampat's answer.
function getSumsBySomeId() {
const criteria = {
attributes: ['some_id', [sequelize.fn('sum', sequelize.col('some_count')), 'some_count_sum']],
group: ['some_id'],
raw: true
};
return Table.getAll(criteria);
}
YIELDS:
{ some_id: 42, some_count_sum: 100 },
{ some_id: 43, some_count_sum: 150 }
...
etc.
Your code should look something like these using ES6 standard.
Table.findAll({ attributes: ['column1', sequelize.fn('count', sequelize.col('column2'))], group: ["Table.column1"] }).then( (result) => { })
**Try this*
Table.findAll({
group: ['column']
})
You need to use row.get('count') to get the count, row.count won't work
The API mentioned at in this answer is correct, but there were a few tricks I was missing in order to actually get the count results out.
As mentioned at: How do I select a column using an alias you need to use .get() for attribute aliased columns for some reason.
And another thing: you need to use parseInt to get an integer out of PostgreSQL count: Postgres sequelize raw query to get count returns string value due to bigint shenanigans.
Minimal runnable example also demonstrating ORDER BY, WHERE and HAVING:
main.js
#!/usr/bin/env node
// https://cirosantilli.com/sequelize-example
const assert = require('assert')
const { DataTypes, Op } = require('sequelize')
const common = require('./common')
const sequelize = common.sequelize(__filename, process.argv[2])
;(async () => {
const UserLikesPost = sequelize.define('UserLikesPost', {
userId: {
type: DataTypes.INTEGER,
},
postId: {
type: DataTypes.INTEGER,
},
}, {})
await UserLikesPost.sync({force: true})
await UserLikesPost.create({userId: 1, postId: 1})
await UserLikesPost.create({userId: 1, postId: 2})
await UserLikesPost.create({userId: 1, postId: 3})
await UserLikesPost.create({userId: 2, postId: 1})
await UserLikesPost.create({userId: 2, postId: 2})
await UserLikesPost.create({userId: 3, postId: 1})
await UserLikesPost.create({userId: 4, postId: 1})
// Count likes on all posts but:
// - don't consider likes userId 4
// - only return posts that have at least 2 likes
// Order posts by those with most likes first.
const postLikeCounts = await UserLikesPost.findAll({
attributes: [
'postId',
[sequelize.fn('COUNT', '*'), 'count'],
],
group: ['postId'],
where: { userId: { [Op.ne]: 4 }},
order: [[sequelize.col('count'), 'DESC']],
having: sequelize.where(sequelize.fn('COUNT', '*'), Op.gte, 2)
})
assert.strictEqual(postLikeCounts[0].postId, 1)
assert.strictEqual(parseInt(postLikeCounts[0].get('count'), 10), 3)
assert.strictEqual(postLikeCounts[1].postId, 2)
assert.strictEqual(parseInt(postLikeCounts[1].get('count'), 10), 2)
assert.strictEqual(postLikeCounts.length, 2)
await sequelize.close()
})()
common.js
const path = require('path');
const { Sequelize } = require('sequelize');
function sequelize(filename, dialect, opts) {
if (dialect === undefined) {
dialect = 'l'
}
if (dialect === 'l') {
return new Sequelize(Object.assign({
dialect: 'sqlite',
storage: path.parse(filename).name + '.sqlite'
}, opts));
} else if (dialect === 'p') {
return new Sequelize('tmp', undefined, undefined, Object.assign({
dialect: 'postgres',
host: '/var/run/postgresql',
}, opts));
} else {
throw new Error('Unknown dialect')
}
}
exports.sequelize = sequelize
package.json:
{
"name": "tmp",
"private": true,
"version": "1.0.0",
"dependencies": {
"pg": "8.5.1",
"pg-hstore": "2.3.3",
"sequelize": "6.5.1",
"sqlite3": "5.0.2"
}
}
and PostgreSQL 13.4 on Ubuntu 21.10. GitHub upstream.
Generated PostgreSQL query:
SELECT
"postId",
COUNT('*') AS "count"
FROM
"UserLikesPosts" AS "UserLikesPost"
WHERE
"UserLikesPost"."userId" != 4
GROUP BY
"postId"
HAVING
COUNT('*') >= 2
ORDER BY
"count" DESC;
JOIN + GROUP BY + aggregate
See: Sequelize query with count in inner join
To create a query like
SELECT key, COUNT(ref) FROM MyModel GROUP BY key
You can do this as follows
const results = await MyModel.findAll({
attributes: ['key', [Sequelize.fn('COUNT', Sequelize.col('ref')), 'count']],
group: ['key']
});
Optionally you can cast the result to something like (MyModel & { count: number })[]
Finally, to extract the count for each row, you'll need to use the getDataValue function. e.g.
results.map(r => r.getDataValue('count'))

Categories