I'm trying to get access to "click_me_123" in the following hash, but I cannot figure it out. I've tried using ['actions']['text']['value'] and [:actions][:text][:value] but I retrieve the appropriate value. Keen to understand what I'm doing wrong.
{ "type"=>"block_actions",
"user"=>{
"id"=>"xxx",
"username"=>"xxx",
"name"=>"xxx",
"team_id"=>"xxx"
},
"api_app_id"=>"xxx",
"token"=>"tYfwns5zvg0g84d58OFVsWrM",
"container"=>{
"type"=>"message",
"message_ts"=>"1643747737.666859",
"channel_id"=>"xxx",
"is_ephemeral"=>false,
"thread_ts"=>"1643747737.666859"
},
"trigger_id" => "3043308548484.1420295660643.1e4a0578e0824d3b69ed371a15842fac",
"team"=>{
"id"=>"T01CC8PKEJX",
"domain"=>"xxx"
},
"enterprise"=>nil,
"is_enterprise_install"=>false,
"channel"=>{
"id"=>"C0316CSCANP",
"name"=>"background-checksdaebc"
},
"message"=>{
"bot_id"=>"B02V6G04XMH",
"type"=>"message",
"text"=>"New check has been started for asd",
"user"=>"U03054J13L1",
"ts"=>"1643747737.666859",
"team"=>"T01CC8PKEJX",
"blocks"=>[
{
"type"=>"section",
"block_id"=>"l2QDl",
"text"=>{
"type"=>"mrkdwn",
"text"=>"New check has been started for asd",
"verbatim"=>false
}
},
{
"type"=>"section",
"block_id"=>"ma=",
"fields"=>[
{
"type"=>"mrkdwn",
"text"=>"*Name:*\nasd asda",
"verbatim"=>false
},
{
"type"=>"mrkdwn",
"text"=>"*Email:*\n<mailto:asd#asdsd.dk|asd#asdsd.dk>",
"verbatim"=>false
},
{
"type"=>"mrkdwn",
"text"=>"*Check started:*\n2022-02-01T20:35:37+00:00",
"verbatim"=>false
},
{
"type"=>"mrkdwn",
"text"=>"*Started by:*\n<#U01CJ7BTT28>",
"verbatim"=>false
}
]
},
{
"type"=>"actions",
"block_id"=>"6Xy",
"elements"=>[
{
"type"=>"button",
"action_id"=>"mjLb",
"text"=>{
"type"=>"plain_text",
"text"=>"Approve",
"emoji"=>true
},
"style"=>"primary",
"value"=>"click_me_123"
},
{
"type"=>"button",
"action_id"=>"EaN2",
"text"=>{
"type"=>"plain_text",
"text"=>"Deny",
"emoji"=>true
},
"style"=>"danger",
"value"=>"click_me_123"
}
]
}
],
"thread_ts"=>"1643747737.666859",
"reply_count"=>1,
"reply_users_count"=>1,
"latest_reply"=>"1643749497.845429",
"reply_users"=>["U03054J13L1"],
"is_locked"=>false,
"subscribed"=>true,
"last_read"=>"1643749497.845429"
},
"state"=>{"values"=>{}},
"response_url"=>"https://hooks.slack.com/actions/xx/xx/xx",
"actions"=>[
{
"action_id"=>"mjLb",
"block_id"=>"6Xy",
"text"=>{
"type"=>"plain_text",
"text"=>"Approve",
"emoji"=>true
},
"value"=>"click_me_123",
"style"=>"primary",
"type"=>"button",
"action_ts"=>"1643751685.126753"
}
]
}
actions is an array so you need to either access a specific index or loop through it.
For example if your hash is called hsh:
hsh.dig('actions', 0, 'value')
This is another way of writing hsh['actions'][0]['value'] but fails gracefully if any of the elements is nil.
or...
hsh['actions'].map { |action| action['value'] }
returns ['click_me_123']
Related
I'm trying to set an attribute of a document inside an array to uppercase.
This is a document example
{
"_id": ObjectId("5e786a078bc3b3333627341e"),
"test": [
{
"itemName": "alpha305102992",
"itemNumber": ""
},
{
"itemName": "beta305102630",
"itemNumber": "P5000"
},
{
"itemName": "gamma305102633 ",
"itemNumber": ""
}]
}
I already tried a lot of thing.
private void NameElementsToUpper() {
AggregationUpdate update = AggregationUpdate.update();
//This one does not work
update.set("test.itemName").toValue(StringOperators.valueOf(test.itemName).toUpper());
//This one also
update.set(SetOperation.set("test.$[].itemName").withValueOfExpression("test.#this.itemName"));
//And every variant in between these two.
// ...
Query query = new Query();
UpdateResult result = mongoTemplate.updateMulti(query, update, aClass.class);
log.info("updated {} records", result.getModifiedCount());
}
I see that Fields class in spring data is hooking into the "$" char and behaving special if you mention it. Do not seem to find the correct documentation.
EDIT: Following update seems to work but I do not seem to get it translated into spring-batch-mongo code
db.collection.update({},
[
{
$set: {
"test": {
$map: {
input: "$test",
in: {
$mergeObjects: [
"$$this",
{
itemName: {
$toUpper: "$$this.itemName"
}
}
]
}
}
}
}
}
])
Any solutions?
Thanks!
For now I'm using which does what i need. But a spring data way would be cleaner.
mongoTemplate.getDb().getCollection(mongoTemplate.getCollectionName(Application.class)).updateMany(
new BasicDBObject(),
Collections.singletonList(BasicDBObject.parse("""
{
$set: {
"test": {
$map: {
input: "$test",
in: {
$mergeObjects: [
"$$this",
{
itemName: { $toUpper: "$$this.itemName" }
}
]
}
}
}
}
}
"""))
);
I want to convert the following nested object into hierarchical data structure
{
"AP":{
"districts":{
"Anantapur":{
"total":{
"confirmed":66593,
"deceased":587,
"recovered":65697
}
},
"Chittoor":{
...
}
}
},
"AR":{
"districts":{....}
}...so on
}
to
[
{
"name":"AP",
"children":[
{
"name":"Anantapur",
"children":[
{
"name":"confirmed",
"value":66593
},
{
"name":"deceased",
"value":587
},
{
"name":"recovered",
"value":65697
}
]
},
{
...
}
]
},...so on
]
How can this be done?...I tried using d3 nest but there is no common key value like
"state":"AP", "state":"AR".
Here "AP" and "AR" are keys themselves. Is there any other method of doing this?
You can use Object.keys(data).map(function(key) { to create an array with an item for every property in your objects. You can nest this approach to get to the desired outcome. Here's a manual solution for your data structure (you could use a recursive function for arbitrarily nested data with a slightly different output, but given the depth of the object and the structure of the output, I have not done that):
var data = { "State One":{
"districts":{
"Region A":{
"total":{
"confirmed":1,
"deceased":2,
"recovered":3
}
},
"Region B":{
"total":{
"confirmed":4,
"deceased":5,
"recovered":6
}
}
}
},
"State Two":{
"districts":{
"Region C":{
"total":{
"confirmed":7,
"deceased":8,
"recovered":9
}
}
}
}
}
var output = Object.keys(data).map(function(key) {
return {
name:key,
children: Object.keys(data[key]["districts"]).map(function(district) {
return {
name:district,
children: Object.keys(data[key]["districts"][district]["total"]).map(function(d) {
return { name: d, value:data[key]["districts"][district]["total"][d] }
})
}
})
}
})
console.log(output);
I have set up a multiple media(images) field called pictures on my project content type on Strapi and I have added 2 projects with pictures containing 4 images each.
I want to query these images in Gatsby using Graphql.
This is my plugins array in gatsby-config.js
plugins: [
`gatsby-plugin-react-helmet`,
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
`gatsby-plugin-sharp`,
`gatsby-transformer-sharp`,
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `gatsby-starter-default`,
short_name: `starter`,
start_url: `/`,
background_color: `#663399`,
theme_color: `#663399`,
display: `minimal-ui`,
icon: `src/images/gatsby-icon.png`,
},
},
{
resolve: `gatsby-source-strapi`,
options: {
apiURL: `http://localhost:1337`,
queryLimit: 1000,
contentTypes: [`project`],
},
}]
This is my graphql query on localhost:8000/___graphql
query MyQuery {
allStrapiProject {
nodes {
pictures {
formats {
thumbnail {
childImageSharp {
fluid {
src
}
}
}
}
}
}
}
}
This is the result I am getting
{
"data": {
"allStrapiProject": {
"nodes": [
{
"pictures": [
{
"formats": {
"thumbnail": null
}
},
{
"formats": {
"thumbnail": {
"childImageSharp": {
"fluid": {
"src": "/static/eb8a7ee6108ecc0e6185aced82c3316b/b4216/167f320a448c2d6ff65acf179ee627e2.jpg"
}
}
}
}
},
{
"formats": {
"thumbnail": null
}
},
{
"formats": {
"thumbnail": null
}
}
]
},
{
"pictures": [
{
"formats": {
"thumbnail": null
}
},
{
"formats": {
"thumbnail": null
}
},
{
"formats": {
"thumbnail": null
}
},
{
"formats": {
"thumbnail": null
}
}
]
}
]
}
}
}
All of the thumbnails contain null except for one.
I have tried running 'gatsby clean' and sometimes get the query output to have same image urls in multiple places even though i don't have repeating images on Strapi.
As of now, there is no "official" way to make it happen. But there is a workaround which creates a custom node in the build process. For a graphql query like below
query MyQuery {
allStrapiPortfolio {
edges {
node {
category {
images {
localFile {
childImageSharp {
fluid {
base64
tracedSVG
srcWebp
srcSetWebp
originalImg
originalName
}
}
}
}
}
}
}
}
}
The code given below creates the localFile node after images. The code should go in gatsby-node.js.
const { createRemoteFileNode } = require(`gatsby-source-filesystem`);
exports.onCreateNode = async ({ node, actions, store, cache }) => {
const { createNode, createNodeField } = actions;
if (node.internal.type !== null && node.internal.type === "StrapiPortfolio") {
for (const category of node.category) {
for (const image of category.images) {
console.log(image);
const fileNode = await createRemoteFileNode({
url: "http://localhost:1337" + image.url,
store,
cache,
createNode,
createNodeId: (id) => image.id.toString(),
});
if (fileNode) {
image.localFile___NODE = fileNode.id;
}
}
}
}
};
Please note that you will have to customize the code depending on your needs. In my solution, I used two for loops because of my data structure. If you're unsure or just want to check if your custom code works, you can simply add a console.log(node) before the first if statement and a console.log(image) after the second for loop(in my case). That should give you an indication about your data structure and in which way you should proceed.
You need to create a localFile___NODE.
First, you need to edit gatsby-node.js file.
const { createRemoteFileNode } = require(`gatsby-source-filesystem`)
exports.onCreateNode = async ({
node,
actions,
store,
cache,
createNodeId,
}) => {
const { createNode } = actions
// replace ".sliderHome" for the name of multiple media in Strapi CMS
let sliderImages = node.sliderHome
// replace “StrapiHome” for your node type
if (node.internal.type === "StrapiHome") {
if (sliderImages.length > 0) {
// sliderImages.forEach(el => console.log(el))
const images = await Promise.all(
sliderImages.map(el =>
createRemoteFileNode({
url: `http://localhost:1337${el.url}`,
parentNodeId: node.id,
store,
cache,
createNode,
createNodeId,
})
)
)
sliderImages.forEach((image, i) => {
image.localFile___NODE = images[i].id
})
}
}
}
later restart Gatsby and now this is your query
query MyQuery {
allStrapiProject {
nodes {
pictures {
localFile{
childImageSharp{
fluid(maxWidth: 1200){
// or for gatsby use ...GatsbyImageSharpFluid_withWebp
src
}
}
}
}
}
}
}
this has worked for me to bring multiple images with a good quality I hope it works for you
Try below, replace the value you need to display:
Here I am the example for the user avatar
query MyQuery {
allStrapiUser {
edges {
node {
id
avatar {
publicURL
childImageSharp {
fluid {
src
aspectRatio
}
}
}
}
}
}
}
and:
const poster = data.allStrapiUser.edges[0].node
<Img fluid={{aspectRatio: 1.6, src: poster.avatar.publicURL}}/>
Bear with me, I will explain this the best I can. Please let me know if more information is needed, I am trying to keep this as brief as possible.
I am using Apollo Server and the 'apollo-datasource-rest' plugin to access a REST API. When attempting to get the property values from a nested array of objects I get a null response for each field/property. In addition, the array being queried is only showing a single iteration when multiple are available.
The field in question is the 'cores' field within the Rocket type, i.e., launch.rocket.firstStage.cores
I have attempted various ways of mapping through 'cores' (thinking this was what it wanted) with no success.
To keep things short and simple I'm only including the code for the specific issue. All other parts of the query are operating as expected.
You can view the API response I am hitting here: https://api.spacexdata.com/v3/launches/77
schema.js
const { gql } = require('apollo-server');
const typeDefs = gql`
type Query {
singleLaunch(flightNumber: Int!): Launch
}
type Launch {
flightNumber: Int!
rocket: Rocket
}
type Rocket {
firstStage: Cores
}
type Cores {
cores: [CoreFields]
}
type CoreFields {
flight: Int
gridfins: Boolean
legs: Boolean
reused: Boolean
landingType: String
landingVehicle: String
landingSuccess: Boolean
}
`;
module.exports = typeDefs;
Data Source - launch.js
const { RESTDataSource } = require('apollo-datasource-rest');
class LaunchAPI extends RESTDataSource {
constructor() {
super();
this.baseURL = 'https://api.spacexdata.com/v3/';
}
async getLaunchById({ launchId }) {
const res = await this.get('launches', {
flight_number: launchId,
});
return this.launchReducer(res[0]);
}
launchReducer(launch) {
return {
flightNumber: launch.flight_number || 0,
rocket: {
firstStage: {
cores: [
{
flight: launch.rocket.first_stage.cores.flight,
gridfins: launch.rocket.first_stage.cores.gridfins,
legs: launch.rocket.first_stage.cores.legs,
landingType: launch.rocket.first_stage.cores.landing_type,
landingVehicle: launch.rocket.first_stage.cores.landing_vehicle,
landingSuccess: launch.rocket.first_stage.cores.landing_success,
},
],
},
};
}
}
module.exports = LaunchAPI;
resolvers.js
module.exports = {
Query: {
singleLaunch: (_, { flightNumber }, { dataSources }) =>
dataSources.launchAPI.getLaunchById({ launchId: flightNumber }),
},
};
Query
query GetLaunchById($flightNumber: Int!) {
singleLaunch(flightNumber: $flightNumber) {
flightNumber
rocket {
firstStage {
cores {
flight
gridfins
legs
reused
landingType
landingVehicle
landingSuccess
}
}
}
}
}
Expected Result
{
"data": {
"singleLaunch": {
"flightNumber": 77,
"rocket": {
"firstStage": {
"cores": [
{
"flight": 1,
"gridfins": true,
"legs": true,
"reused": true,
"landingType": "ASDS",
"landingVehicle": "OCISLY",
"landSuccess": true,
},
{
"flight": 1,
"gridfins": true,
"legs": true,
"reused": false,
"landingType": "RTLS",
"landingVehicle": "LZ-1",
"landSuccess": true
},
{
"flight": 1,
"gridfins": true,
"legs": true,
"reused": false,
"landingType": "RTLS",
"landingVehicle": "LZ-2",
"landSuccess": true
},
]
}
},
}
}
}
Actual Result (Through GraphQL Playground)
{
"data": {
"singleLaunch": {
"flightNumber": 77,
"rocket": {
"firstStage": {
"cores": [
{
"flight": null,
"gridfins": null,
"legs": null,
"reused": null,
"landingType": null,
"landingVehicle": null,
"landingSuccess": null
}
]
}
},
}
}
}
Any suggestions as to what I am doing wrong here would be greatly appreciated. Again, let me know if more information is needed.
Thank you!
Missing base url
There should be
await this.get( this.baseURL + 'launches'
IMHO there should be a map used within launchReducer to return an array, sth like:
launchReducer(launch) {
return {
flightNumber: launch.flight_number || 0,
rocket: {
firstStage: {
cores: launch.rocket.first_stage.cores.map(core => ({
flight: core.flight,
gridfins: core.gridfins,
legs: core.legs,
landingType: core.landing_type,
landingVehicle: core.landing_vehicle,
landSuccess: core.land_success,
})),
},
},
};
}
.map(core => ({ is for returning object [literal], the same as/shorter version of .map(core => { return {
I would like to filter from REST API by nested data. For example this object:
[
{
"name": "Handmade Soft Fish",
"tags": "Rubber, Rubber, Salad",
"categories": [
{
"name": "women",
"id": 2,
"parent_id": 0,
"permalink": "/women"
},
{
"name": "kids",
"id": 3,
"parent_id": 0,
"permalink": "/kids"
}
]
},
{
"name": "Tasty Rubber Soap",
"tags": "Granite, Granite, Chair",
"categories": [
{
"name": "kids",
"id": 3,
"parent_id": 0,
"permalink": "/kids"
}
]
}
]
is comming by GET /api/products?filter[include]=categories
and i would like to get only products which has category name "women". How do this?
LoopBack does not support filters based on related models.
This is a limitation that we have never had bandwidth to solve, unfortunately :(
For more details, see the discussion and linked issues here:
Filter on level 2 properties: https://github.com/strongloop/loopback/issues/517
Filter by properties of related models (use SQL JOIN in queries): https://github.com/strongloop/loopback/issues/683
Maybe you want to get this data by the Category REST API. For example:
GET /api/categories?filter[include]=products&filter[where][name]=woman
The result will be a category object with all products related. To this, will be necessary declare this relation on the models.
Try like this.It has worked for me.
const filter = {
where: {
'categories.name': {
inq: ['women']**strong text**
}
}
};
Pass this filter to request as path parameters and the request would be like bellow
GET /api/categoriesfilter=%7B%22where%22:%7B%categories.name%22:%7B%22inq%22:%5B%women%22%5D%7D%7D%7D
Can you share how it looks like without filter[include]=categorie, please ?
[edit]
after a few questions in comment, I'd build a remote method : in common/models/myModel.js (inside the function) :
function getItems(filter, categorieIds = []) {
return new Promise((resolve, reject) => {
let newInclude;
if (filter.hasOwnProperty(include)){
if (Array.isArray(filter.include)) {
newInclude = [].concat(filter.include, "categories")
}else{
if (filter.include.length > 0) {
newInclude = [].concat(filter.include, "categories");
}else{
newInclude = "categories";
}
}
}else{
newInclude = "categories";
}
myModel.find(Object.assign({}, filter, {include: newInclude}))
.then(data => {
if (data.length <= 0) return resolve(data);
if (categoriesIds.length <= 0) return resolve(data);
// there goes your specific filter on categories
const tmp = data.filter(
item => item.categories.findIndex(
categorie => categorieIds.indexOf(categorie.id) > -1
) > -1
);
return resolve(tmp);
})
}
}
myModel.remoteMethod('getItems', {
accepts: [{
arg: "filter",
type: "object",
required: true
}, {
arg: "categorieIds",
type: "array",
required: true
}],
returns: {arg: 'getItems', type: 'array'}
});
I hope it answers your question...