jq: how to add double quotes for string values - jq

given this JSON:
{
"stringKey": "this is a string",
"numberKey": 1234,
"jsonKey": [
{"numberKey": 1, "stringKey": "0x" }
]
}
and this jq expression
to_entries|map("export let " + .key + " = " + (.value | tostring)) | .[]
I get this:
export let stringKey = this is a string
export let numberKey = 1234
export let jsonKey = [{"numberKey":1,"stringKey":"0x"}]
however I want this (note double quotes around this is a string):
export let stringKey = "this is a string"
export let numberKey = 1234
export let jsonKey = [{"numberKey":1,"stringKey":"0x"}]
jqplay snippet can be found https://jqplay.org/s/MYdILy4Xfw3
any help? thanks!

Use tojson, not tostring. It does exactly what you need for all data types.
to_entries|map("export let " + .key + " = " + (.value | tojson)) | .[]
Check it online.

To get a JSON-encoded output, use tojson instead of tostring:
jq -r 'to_entries[] | "export let " + .key + " = " + (.value | tojson)'
export let stringKey = "this is a string"
export let numberKey = 1234
export let jsonKey = [{"numberKey":1,"stringKey":"0x"}]
Demo
With the same effect, you can also use the #json syntax and provide the value through string interpolation:
jq -r 'to_entries[] | "export let " + .key + #json " = \(.value)"'
export let stringKey = "this is a string"
export let numberKey = 1234
export let jsonKey = [{"numberKey":1,"stringKey":"0x"}]
Demo
Note: For simplicity, I have also turned map(…) | .[] into .[] | ….

Related

How to get a message from a Chat, after using a command and storing that message as a variable (Pyrogram)?

So I am kinda new with Pyrogram and I want to create my own Genshin Bot. After using the command redeem code, I want the message to be taken and stored as variable. so can anyone help me with that
after taking the code as input from user I would be able to use genshin.py api wrapper to redeem code. Just need help with getting message and storing it as variable.
import genshin
import os
from dotenv import load_dotenv
from pyrogram import Client, filters
load_dotenv()
global chatid
chatid = 842544591
global uid
uid = os.getenv("uid")
ltuid = os.getenv("ltuid")
ltoken = os.getenv("ltoken")
cookie_token = os.getenv("cookie_token")
api_id = os.getenv("api_id")
api_hash = os.getenv("api_hash")
bot_token = os.getenv("bot_token")
cookies = {"ltuid": ltuid,
"ltoken": ltoken,
"cookie_token": cookie_token,
"uid": uid}
client = genshin.Client(cookies)
bot = Client(
"Genshin Bot",
api_id=api_id,
api_hash=api_hash,
bot_token=bot_token
)
#bot.on_message(filters.command('start'))
def start_command(bot, message):
message.reply_text(
"Welcome to Genshin Auto Tasks Bot.\nFor Getting Started Use /help command.")
#bot.on_message(filters.command('help'))
def help_command(bot, message):
message.reply_text("This is Bot's Help Section")
#bot.on_message(filters.command('notes'))
async def get_notes(bot, message):
data = await client.get_full_genshin_user(uid)
notes = await client.get_notes(uid)
active_days = (data.stats.days_active)
total_characters = (data.stats.characters)
abyss_total_stars = (data.abyss.previous.total_stars)
resin_count = notes.current_resin
resin_recovery_time = notes.remaining_resin_recovery_time
await message.reply_text("Pranay Asia" + "\n" +
"uid : " + str(uid) + "\n" +
"-----------------------------------------------------------------" + "\n" +
"Resin Count: " + str(resin_count) + "/" + str(notes.max_resin) + "\n" +
"Countdown to next resin recovery: " + str(resin_recovery_time) + "\n" +
"Total No. of Active Days: " + str(active_days) + "\n" +
"Total No. of Characters: " + str(total_characters) + "\n" +
"Total Stars in Abyss: " + str(abyss_total_stars)
)
#bot.on_message(filters.command('redeemcode'))
def redeem_code(bot, message):
message.reply_text("Send the Code to Redeem")
bot.run()
try message.text
I use it as a userbot but nothing changes so much. This piece of code saves the sent message to a variable and filters out the command itself. For a bot it will be easier: answer = message.text
#app.on_message(filters.command("ns", prefixes=".") & filters.text)
async def EXAMPLE(_,msg):
orig_text = msg.text.split(".ns ", maxsplit=1)[1]
text = orig_text

Cannot index array with string "xxx"

I have a json file as this,
# cat input.json
{
"foo":[
"key1",
"key2"
],
"bar": "key3"
}
And I want to join all those strings ("key1", "key2", key3") into one string, and I define the filter as this,
# cat filter.jq
[.[] | . as { foo: $names, bar: $name} | {
name1: [ $names | range(0;length) as $i | {
key1: ($names[$i])
}],
name2: {
key2: $name
}
} | {
values: (.name1 | map(.key1) | join(" ") + .name2.key2)
}]
But this doesn't work,
# <input.json jq --slurp --from-file filter.jq > output.json
jq: error (at <stdin>:8): Cannot index array with string "name2"
What's wrong going here?
btw. concat with a string seems works.
values: (.name1 | map(.key1) | join(" ") + "key3")
The problem is underspecified, but you might wish to consider:
[.. | strings] | join(" ")
or similar.

Is there a way to check nested option values in one pattern in F#?

Let's pretend we have the following types:
type Message {
text : Option<string>
}
type Update {
msg : Option<Message>
}
How do I match it in one line, like in C# using null-conditional operator i.e update?.msg?.text ?
Is there a way to do it like this?:
match msg, msg.text with
| Some msg, Some txt -> ...
| None -> ...
because I don't want to be writing 2 nested match expressions.
You have two Record types (missing the "=" in your example). To match some variable of Update type, you could do as follows:
type Message = { text : Option<string> }
type Update = { msg : Option<Message> }
let u = {msg = Some({text = Some "text"})}
//all 3 possible cases
match u with
| {msg = Some({text = Some t})} -> t
| {msg = Some({text = None})} -> ""
| {msg = None} -> ""

How to parse a custom key/value pair string into a JSON object in Azure Data Explorer?

I needed to parse a string of properties to a JSON object. Here is the input format:
"var1=[val1] & var2=[val2] & var3=[val3] & var4=[val4]"
And the desired output:
{
"var1": "val1",
"var2": "val2",
"var3": "val3",
"var4": "val4"
}
I have the answer, see below...
an alternative method would be using extract_all(), then 'converting' the array into a property bad using pack() and make_bag():
print str = "var1=[val1] & var2=[val2] & var3=[val3] & var4=[val4]"
| project Properties = extract_all(#"(?P<key>\w+)?=\[(?P<value>.*?)\]", dynamic(["key","value"]), str)
| mv-apply Properties on (
summarize make_bag(pack(tostring(Properties[0]), Properties[1]))
)
Thanks Ziad Hammoud for providing this cool workaround!
print str = "var1=[val1] & var2=[val2] & var3=[val3] & var4=[val4]"
| extend str = replace("\\] & ", "&", replace("=\\[", "=", str))
| project Properties = parse_urlquery(str)['Query Parameters']
| where Properties.var2== "val2"

Interaction between {} and select

Here's my test data:
[
{
"id": "id-1",
"tags": {
"key": "name",
"value": "name-1"
}
},
{
"id": "id-2"
}
]
I'm trying to simplify the output, to show the 'name' field if present, and always show the id. For example, this script almost works:
~ $ cat testdata | jq '.[] | {id, name: .tags.value}'
{
"id": "id-1",
"name": "name-1"
}
{
"id": "id-2",
"name": null
}
When I try to add in a guard against .keys not existing and filter for the section of 'keys' I care about, here's what happens:
~ $ cat testdata | jq '.[] | {id, name: (select(.tags.key == "name") | .tags.value)}'
{
"id": "id-1",
"name": "name-1"
}
I assume {} is somehow ending up with a zero-length array instead of 'null'. What should I be using instead of |? What am I misunderstanding?
I ended up solving the problem using: [POSSIBLY_MATCHED_EXPRESSION][0], in this case:
cat testdata | jq '.[] | {id, name: ([select(.tags.key == "name") | .tags.value][0])}'
If I'm understanding correctly, if you wanted to include a name only if it existed, I'd do this:
map({id} + with_entries(select(.key == "tags") | .value))
Otherwise if you don't mind null names:
map({id, name: with_entries(select(.key == "tags") | .value) | .name})
Here's a more general solution if you have other "tags" so it's not hardcoded to only accept name values.
This assumes that any object value is actually a key/value pair.
map(with_entries(if .value | type == "object" then .value else . end))
Or if tags is the only dynamic property:
map(with_entries(if .key == "tags" then .value else . end))
If the goal is to produce:
{"id":"id-1","name":"name-1"}
{"id":"id-2"}
then the following three expressions are essentially equivalent solutions:
.[] | if .tags.key == "name" then {id, name: .tags.value} else {id} end
.[] | {id} + (if .tags.key == "name" then {name: .tags.value} else {} end)
.[] | (select(.tags.key == "name") | {id, name: .tags.value}) // {id}
You could just add
| if .name == null then del(.name) else . end
to the end of your filter to get rid of the .name key when its value is null.
With your test data, the following
.[]
| {id, name:.tags.value }
| if .name == null then del(.name) else . end
produces
{
"id": "id-1",
"name": "name-1"
}
{
"id": "id-2"
}

Resources