How to query jsonb value in where clause? - node.js

I use PostgreSQL with Sequelize. I have one templates table that has one column named location and its type is JSONB.
userLocationIds is an array of Location. I wrote a function that want to filter the template as its Location that the value of it should be included userLocationIds.
But when I run get empty array. How can I solve it?
This is my code:
export const getList = async (oId, userId) => {
const userLocationIds = await UserLocation.findAll({
where: { userId: userId},
attributes:["locationId"]
}).map((location) => {
return location.locationId
})
const templatesList = await Templates.findAll({
where: { oId , location: { [Op.in]: userLocationIds }},
})
return templatesList
}
my template is like:
[
{
"id": 10,
"templateName": "test",
"orgId": "7549",
"location": [
1,
316,
317
],
"items": null,
"templateType": "cxxred",
},
{
"id": 11,
"templateName": "test2",
"orgId": "7549",
"location": [
2
316,
327
],
"items": null,
"templateType": "cxxred",
}]

Related

Unable to retrive ordered job list from Google Transcoder API

i'm using the node.js client library of google transcoder api. I'm able to retrive a paginated list of some jobs, but i'm not able to order elements by start date. Here my codes:
const { TranscoderServiceClient } = require('#google-cloud/video-transcoder').v1;
class TranscoderApiController {
constructor() {
this.projectId = process.env.GOOGLE_CLOUD_PROJECT;
this.location = process.env.TASK_LOCATION;
}
async getEntries(req, res, next) {
const params = {
pageSize: req.query.pageSize ? parseInt(req.query.pageSize) : 10,
pageToken: req.query.pageToken,
filter: req.query.filter,
orderBy: req.query.orderBy
}
const client = new TranscoderServiceClient();
const result = await client.listJobs({
parent: client.locationPath(this.projectId, this.location),
pageSize: params.pageSize,
orderBy: 'createTime.seconds'
}, {
autoPaginate: false
});
if (result.length == 3 && result[2] != undefined) {
return result[2];
} else {
return result[1];
}
}
}
module.exports = new TranscoderApiController();
When i call the getEntries method i receive the following error:
"3 INVALID_ARGUMENT: The request was invalid: sort order \"createTime.seconds\" is unsupported"
If i remove the orderBy: 'createTime.seconds' line then the api works but is not ordered as i want. The result is something like that (i abbreviate the json):
{
"jobs": [
{
"labels": {},
"name": "projects/<id>/locations/europe-west1/jobs/<uuid>",
"inputUri": "",
"outputUri": "",
"state": "SUCCEEDED",
"createTime": {
"seconds": "1656602896",
"nanos": 386772728
},
"startTime": {
"seconds": "1656602900",
"nanos": 755000000
},
"endTime": {
"seconds": "1656603062",
"nanos": 428000000
},
"ttlAfterCompletionDays": 30,
"error": null,
"config": {
"inputs": [
{
"key": "input0",
"uri": "gs://<url>/render_md.mp4",
"preprocessingConfig": null
}
],
"editList": [...],
"elementaryStreams": [...],
"muxStreams": [...],
"manifests": [],
"adBreaks": [],
"spriteSheets": [],
"overlays": [],
"output": {
"uri": "gs://<url>/md.mp4/"
},
"pubsubDestination": {
"topic": "projects/<id>/topics/transcoder_api"
}
},
"jobConfig": "config"
},
...
],
"unreachable": [],
"nextPageToken": "Co8BCjgKDGV1cm9wZS13ZXN0MRIZdHJhbnNjb2Rlci5nb29nbGVhcGlzLmNvbRgBII..."
}
As you can see each job have the startTime.seconds property. I follow the syntax described here:
https://google.aip.dev/132#ordering
Any support to solve the ordered issue is appreciated.

Dynamodb scan on array of objects Filter Expression

I want to scan dynamodb using filter on product_id showing in below json of table.
Can anybody explain how to do scanning using filter of product_id.
Wants to scan dynamodb table data using documentclient.
Wants to find all fields which has product_id: something
{
"mandi_id": 1,
"product": [
{
"updated_price": 24,
"product_id": 2,
"last_price": 23
},
{
"updated_price": 24,
"product_id": 5,
"last_price": 23
}
],
"status": "active",
"createdAt": "2022-04-21T08:23:41.774Z",
"mandiCloseTime": "4pm",
"mandi_description": "anaj mandi",
"mandi_name": "gaziabad anaj mandi",
"state": "uttar pradesh",
"city": "gaziabad",
"main_image_s3": "",
"mandi_latlong": {
"lng": 77.48325609999999,
"lat": 28.680346
},
"mandiOpenTime": "10am",
"updatedAt": "2022-04-21T08:23:41.774Z",
"address_name": "gavindpuram",
"landmark_name": "mandi",
"village": "gaziabad",
"postal": "201013"
}
I have tried the following set of code but it is returning empty array list
var params = {
TableName: "dev-agrowave-mandi-management",
// Select: "ALL_ATTRIBUTES"
FilterExpression: "contains(#product,:product)",
ExpressionAttributeNames: {
"#product": "product",
},
ExpressionAttributeValues: { ":product": {"product_id":parseInt(id)}
}
};
let lastEvaluatedKey = 'dummy'; // string must not be empty
const itemsAll = [];
while (lastEvaluatedKey) {
const data = await docClient.scan(params).promise();
itemsAll.push(...data.Items);
lastEvaluatedKey = data.LastEvaluatedKey;
if (lastEvaluatedKey) {
params['ExclusiveStartKey'] = lastEvaluatedKey;
}
}
return {msg:itemsAll,params:params};

How to pull out object heading from an array

I have a JSON response structure like this
{
"_id": "620e97d76ca392a43097cca6",
"user": "620295cbd67ece90802d2522",
"orderId": "EnrL7C",
"Items": [
{
"product": {
"name": "Fresh Salad",
"id": "61f2911723ff35136c98ad3e"
},
"quantity": 1,
"price": 1250,
"_id": "620e97d76ca392a43097cca7"
},
],
}
But i want the product not to be an object, so it should look like this
{
"_id": "620e97d76ca392a43097cca6",
"user": "620295cbd67ece90802d2522",
"orderId": "EnrL7C",
"Items": [
{
"name": "Fresh Salad",
"id": "61f2911723ff35136c98ad3e",
"quantity": 1,
"price": 1250,
"_id": "620e97d76ca392a43097cca7"
},
],
}
This is my code responsible for the response output
exports.getOrder = (req,res) => {
Order.findOne({orderId: 'EnrL7C'})
.populate("Items.product", "name")
.exec((error, order) => {
if(error) return res.status(400).json({ error });
if (order) {
return res.json(order);
}else{
return res.json(['No order found']);
}
});
Sometimes when I'm too lazy to look up all the mongoose documentation and figure out what version I'm on etc, I use the .lean() to just convert it to a normal JS object, which I'm way more comfortable with.
exports.getOrder = (req, res) => {
Order.findOne({ orderId: "EnrL7C" })
.lean() // add lean
.populate("Items.product", "name")
.exec((error, order) => {
if (error) return res.status(400).json({ error });
if (order) {
// fix the structure in javascript
order.Items = order.Items.map((item) => {
const flat = {
...item.product,
...item,
};
delete flat.product;
return flat;
});
return res.json(order);
} else {
return res.json(["No order found"]);
}
});
};
Let me know if that doesn't work, so I can update the answer.

Can you 'filter' the columns from a second leftJoinAndMapOne?

Can the columns of a second leftJoinAndMapOne() be 'filtered' so that it only returns the columns or values that I need inside the object?
Query Builder:
const favorites = await this.favoritesRepo.createQueryBuilder('favorite')
.where('favorite.user_id = :token', { token })
.leftJoinAndMapOne('favorite.item', 'favorite.item_id', 'items')
.select(['favorite.id'])
.addSelect([
'items.title',
'items.description',
'items.price',
'items.stock',
])
.leftJoinAndMapOne(
'items.photos',
PhotosEntity,
'photos',
'favorite.item_id = photos.subject_id and photos.subject_type = :item',
{item: 'item'}
)
return paginate<Favorite>(favorites, options)
Output (GET):
//...
{
"id": 32,
"item": {
"title": "Foo",
"description": "Buzz",
"price": 250.99,
"stock": 10,
"photos": {
"id": 2,
"createdAt": "2021-12-04T04:55:02.408Z",
"url": "https://images.unsplash.com/photo-1633114128729-0a8dc13406b9?ixlib=rb-1.2.1&ixid=MnwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=870&q=80",
"width": 324,
"height": 281,
"size": 42,
"entityId": 18,
"entityType": "item",
"redirectUrl": "https://facebook.com/"
}
}
},
//...
Expected Output:
//...
{
"id": 32,
"item": {
"title": "Foo",
"description": "Buzz",
"price": 250.99,
"stock": 10,
"photos": {
"url": "https://images.unsplash.com/photo-1633114128729-0a8dc13406b9?ixlib=rb-1.2.1&ixid=MnwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=870&q=80"
}
}
},
//...
Any suggestions or changes that I should make to make the output as expected? 🤔
.leftJoinAndMapOne(
'items.image',
PhotosEntity,
'photos',
'favorite.item_id = photos.subject_id and photos.subject_type = :item',
{item: 'item'}
)
.addSelect('photos.url')
I tried with .select () or .addSelect () but it doesn't filter columns from photos.
I already resolved it
Query Builder:
const favorites = await this.favoritesRepo.createQueryBuilder('favorite')
.where('favorite.user_id = :token', { token })
.leftJoinAndMapOne('favorite.item', 'favorite.item_id', 'items')
.leftJoinAndMapOne(
'items.photos',
PhotosEntity,
'photos',
'favorite.item_id = photos.subject_id and photos.subject_type = :item',
{item: 'item'}
)
.select(['favorite.id'])
.addSelect([
'items.title',
'items.description',
'items.price',
'items.stock',
'photos.url',
])

Using pull in mongoose model

Should this work? I am trying to remove a single subdocument (following) from a document (this) in the UserSchema model.
UserSchema.methods.unFollow = function( id ) {
var user = this
return Q.Promise( function ( resolve, reject, notify ) {
var unFollow = user.following.pull( { 'user': id } )
console.log( unFollow )
user.save( function ( error, result ) {
resolve( result )
})
})
}
These are the schemas:
var Follows = new mongoose.Schema({
user: String,
added: Number
})
var UserSchema = new mongoose.Schema({
username: {
type: String,
required: true,
unique: true
},
following: [ Follows ]
})
user-controller.js
/*
Unfollow user.
*/
exports.unFollow = function ( req, res ) {
User.findOne( { token: req.token }, function ( error, user ) {
user.unfollow( req.body.id )
.onResolve( function ( err, result ) {
if ( err || !result ) return res.status( 500 ).json( "User could not be unfollowed." )
return res.status( 200 ).json( "User unfollowed." )
})
})
}
user-model.js
/*
Unfollow a user.
*/
UserSchema.method( 'unfollow', function unfollow ( id ) {
this.following.pull( { user: id } )
return this.save()
})
You generally assign methods using the method function:
UserSchema.method('unFollow', function unFollow(id) {
var user = this;
user.following.pull({_id: id});
// Returns a promise in Mongoose 4.X
return user.save();
});
Also, as noted, you don't need to use Q as save will return a mongoose promise.
UPDATE: Mongoose's array pull method will work with matching primitive values but with subdocument objects it will only match on _id.
UPDATE #2: I just noticed your updated question shows that your controller is doing a lookup first, modifying the returned document and then saving the document back to the server. Why not create a static rather than a method to do what you want? This has the added bonus of being a single call to the DB rather than two per operation.
Example:
UserSchema.static('unfollow', function unfollow(token, id, cb) {
var User = this;
// Returns a promise in Mongoose 4.X
// or call cb if provided
return User.findOneAndUpdate({token: token}, {$pull: {follows: {user: id}}}, {new: true}).exec(cb);
});
User.unfollow(req.token, req.body.id).onResolve(function (err, result) {
if (err || !result) { return res.status(500).json({msg: 'User could not be unfollowed.'}); }
return res.status(200).json({msg: 'User unfollowed.'})
});
Bonus follow static:
UserSchema.static('follow', function follow(token, id, cb) {
var User = this;
// Returns a promise in Mongoose 4.X
// or call cb if provided
return User.findOneAndUpdate({token: token}, {$push: {follows: {user: id}}}, {new: true}).exec(cb);
});
User.follow(req.token, req.body.id).onResolve(function (err, result) {
if (err || !result) { return res.status(500).json({msg: 'User could not be followed.'}); }
return res.status(200).json({msg: 'User followed.'})
});
NOTE: Used in "mongoose": "^5.12.13".
As for today June 22nd, 2021, you can use $in and $pull mongodb operators to remove items from an array of documents :
Parent Document :
{
"name": "June Grocery",
"description": "Some description",
"createdDate": "2021-06-09T20:17:29.029Z",
"_id": "60c5f64f0041190ad312b419",
"items": [],
"budget": 1500,
"owner": "60a97ea7c4d629866c1d99d1",
}
Documents in Items array :
{
"category": "Fruits",
"bought": false,
"id": "60ada26be8bdbf195887acc1",
"name": "Kiwi",
"price": 0,
"quantity": 1
},
{
"category": "Toiletry",
"bought": false,
"id": "60b92dd67ae0934c8dfce126",
"name": "Toilet Paper",
"price": 0,
"quantity": 1
},
{
"category": "Toiletry",
"bought": false,
"id": "60b92fe97ae0934c8dfce127",
"name": "Toothpaste",
"price": 0,
"quantity": 1
},
{
"category": "Toiletry",
"bought": false,
"id": "60b92ffb7ae0934c8dfce128",
"name": "Mouthwash",
"price": 0,
"quantity": 1
},
{
"category": "Toiletry",
"bought": false,
"id": "60b931fa7ae0934c8dfce12d",
"name": "Body Soap",
"price": 0,
"quantity": 1
},
{
"category": "Fruit",
"bought": false,
"id": "60b9300c7ae0934c8dfce129",
"name": "Banana",
"price": 0,
"quantity": 1
},
{
"category": "Vegetable",
"bought": false,
"id": "60b930347ae0934c8dfce12a",
"name": "Sombe",
"price": 0,
"quantity": 1
},
Query :
MyModel.updateMany(
{ _id: yourDocumentId },
{ $pull: { items: { id: { $in: itemIds } } } },
{ multi: true }
);
Note: ItemIds is an array of ObjectId. See below :
[
'60ada26be8bdbf195887acc1',
'60b930347ae0934c8dfce12a',
'60b9300c7ae0934c8dfce129'
]

Resources