mosquito_sub to jq get value - jq

I have MQTT mosquitto_sub running on linux bash that outputs this JSON data received from power plug:
#mosquitto_sub -t stat/sensors/# | jq -r '.'
{
"Status": {
"Module": 52,
"FriendlyName": [
"stecker2"
],
"Topic": "sensors",
"ButtonTopic": "0",
"Power": 0,
"PowerOnState": 3,
"LedState": 1,
"SaveData": 1,
"SaveState": 1,
"SwitchTopic": "0",
"SwitchMode": [
0,
0,
0,
0,
0,
0,
0,
0
],
"ButtonRetain": 0,
"SwitchRetain": 0,
"SensorRetain": 0,
"PowerRetain": 0
}
}
How can I query for the "Power": 0 value only? I only need the "0".
I tried with
jq -r '.Power'
but that only returns
null

One way is to “drill down”:
.Status.Power

Related

How to count specific no of items in Postman response

I am new to postman. I have response and I want to count how many items with equipment_id =53
Here is my code which I tried but I couldn't see any output in console.
Response
[
{
"id": 373,
"user_id": 119118855,
"location_id": 9999,
"duration": 0,
"watts": 0,
"timestamp": "2019-07-12T00:00:00.000Z",
"equipment_id": 53,
"name": "10 Ride",
"equipment_name": "Bike2"
},
{
"id": 376,
"user_id": 119118855,
"location_id": 9999,
"duration": 0,
"watts": 0,
"timestamp": "2019-06-13T00:00:00.000Z",
"equipment_id": 53,
"name": "10 min Ride",
"equipment_name": "Bike2"
},
{
"id": 338,
"user_id": 119118855,
"location_id": 9999,
"duration": 0,
"watts": 0,
"timestamp": "2019-07-12T00:00:00.000Z",
"equipment_id": 17,
"name": "20 min Ride",
"equipment_name": "Bike"
},
]
Postman script I tried:
pm.test("count of records with equipment id 53",function(){
const jsonData = pm.response.json();
var count = jsonData.length;
//console.log(count);
function noofrecords (){
_each(count.equipment_id).to.include(53);
count++;
console.log("Count:" + noofrecords);
May I know how to write script to get count of equipment_id =53
Answer should be 2 here, but I am not getting it.
count = jsonData.filter( a => a["equipment_id"] === 53 ).length
this gives the count, here we are using array.filter to get all objects with equipment_id 53

Firebase Cloud Functions forEach()

So Below is the JSON for my firebase databse:
{
"1YrpX2W2xnMPoy4YGpZcOE0xJ5g2" : {
"email" : "muyi#hotmail.com",
"fullname" : "Muyiz",
"selection" : [ 1, 2, 3, 4, 5, 6 ],
"teamname" : "awon",
"total" : 12,
"userName" : "motmail.com",
"week1" : 0,
"week10" : 0,
"week11" : 0,
"week12" : 0,
"week2" : 0,
"week3" : 0,
"week4" : 0,
"week5" : 0,
"week6" : 12,
"week7" : 0,
"week8" : 0,
"week9" : 0
},
"6K9rQiZQ3jaV38WWtDbNwxhqIwc2" : {
"email" : "domi#gmail.com",
"fullname" : "Dai",
"selection" : 0,
"teamname" : "Bayern Neverlosin'",
"total" : 0,
"userName" : "dai#gmail.com",
"week1" : 0,
"week10" : 0,
"week11" : 0,
"week12" : 0,
"week2" : 0,
"week3" : 0,
"week4" : 0,
"week5" : 0,
"week6" : 0,
"week7" : 0,
"week8" : 0,
"week9" : 0
},
"9OgN4HyMtARaQEQV1mKQ5lyE1992" : {
"email" : "jonail.com",
"fullname" : "Jon",
"selection" : [ 40, 8, 10, 24, 18, 34 ],
"teamname" : "Chad fc",
"total" : 0,
"userName" : "jojin#gmail.com",
"week1" : 0,
"week10" : 0,
"week11" : 0,
"week12" : 0,
"week2" : 0,
"week3" : 0,
"week4" : 0,
"week5" : 8,
"week6" : 0,
"week7" : 0,
"week8" : 0,
"week9" : 0
},
"AGVZAUye5ZbZgvwCOpMeDkoOsEU2" : {
"email" : "ihe#gmail.com",
"fullname" : "Emeka Iheme",
"selection" : 0,
"teamname" : "Young Money",
"total" : 0,
"userName" : "ihem#gmail.com",
"week1" : 0,
"week10" : 0,
"week11" : 0,
"week12" : 0,
"week2" : 0,
"week3" : 0,
"week4" : 0,
"week5" : 0,
"week6" : 0,
"week7" : 0,
"week8" : 0,
"week9" : 0
}
}
Below is the cloud function I use to that has kind of worked :
exports.update = functions.database.ref('/users/{user.uid}')
.onWrite(event=>{
console.log ('it banged!');
const uid = event.data.key;
ref = admin.database().ref(`/users/`+ uid + `week1`);
pref1 = admin.database().ref("Player").child("playerweek8");
ref2 = admin.database().ref(`/users/` + uid `/` );
if(n === 4){
ref.set(10);
}
The ISSUE
The issue is that the code only work when there is a change in the respective user. For example, if I change a write in the user with uid 1YrpX2W2xnMPoy4YGpZcOE0xJ5g2 it sets 10 to the ref. But what I had aimed for is a change to the user node to result in ref.set(10) for each of the users. Is that not possible? Sorry as you could probably guess, I am new to firebase. Thanks in advance.
If you are new to Firebase and JavaScript, Cloud Functions for Firebase is not the best way to learn it. I recommend first reading the Firebase documentation for Web developers and/or taking the Firebase codelab for Web developer. They cover many basic JavaScript, Web and Firebase interactions. After those you'll be much better equipped to write code for Cloud Functions too. But I'll try to explain why your code doesn't/can't work and how I'd approach it below.
You're using a database trigger, which only gets invoked when there is a write to the database that matches the criteria you specify. So your:
exports.update = functions.database.ref('/users/{user.uid}').onWrite(
Only triggers when there is a write to a user node.
If you want to do batch processing of all users, you'll probably want use a HTTP trigger:
exports.updateUsers = functions.https.onRequest((req, res) => {
...
});
When you deploy this function, it give you a URL. You can trigger the function by calling the URL, or by simply opening it in a browser.
In the function you'll want to load the users from the database, and process them. The total will leave you with something like:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.updateUsers = functions.https.onRequest((req, res) => {
admin.database().ref("users").once("value").then((snapshot) => {
snapshot.forEach((userSnap) => {
userSnap.child("week1").set(10);
});
});
});
You'll need to modify the code in the function to your needs. I mostly focused on showing the main concepts: triggering via HTTP, and then loading data from the database.

Backreferences in jq like sed or vi?

I have the following string in my input to jq:
"\n*blah\n**tim\nbob was here\n*item1\n**item2\n"
And I'm able to match the first \n* with the following:
[match("(\n\\*[A-Za-z0-9]*\n)";"g")]
Which gives me the following matches:
[
{
"offset": 0,
"length": 7,
"string": "\n*blah\n",
"captures": [
{
"offset": 0,
"length": 7,
"string": "\n*blah\n",
"name": null
}
]
},
{
"offset": 25,
"length": 8,
"string": "\n*item1\n",
"captures": [
{
"offset": 25,
"length": 8,
"string": "\n*item1\n",
"name": null
}
]
}
]
My goal however, is to search for these and add an extra \n to the start of the matched \n* lines.
I don't appear to be able to do backreferences using gsub, so is there a similar functionality to what can be done in sed and vi using backreference matches in jq?
Here is a demonstration using a named capture ?<a> with sub and gsub:
$ jq -Mn '
"\n*blah\n**tim\nbob was here\n*item1\n**item2\n"
| sub("(?<a>\n\\*[A-Za-z0-9]*\n)";"\n\(.a)";"g")
, gsub("(?<a>\n\\*[A-Za-z0-9]*\n)";"\n\(.a)")
'
output
"\n\n*blah\n**tim\nbob was here\n\n*item1\n**item2\n"
"\n\n*blah\n**tim\nbob was here\n\n*item1\n**item2\n"

unable to filter object with name `end` using JQ

I am trying to parse a json file using jq.
$cat ipres.txt
{
"start": {
"connected": [{
"socket": 5,
"local_host": "10.8.0.3",
"local_port": 36068,
"remote_host": "10.8.0.2",
"remote_port": 5201
}],
"version": "iperf 3.1.2",
"system_info": "Linux sid-Vostro-3700 3.13.0-77-generic #121-Ubuntu SMP Wed Jan 20 10:50:42 UTC 2016 x86_64",
"timestamp": {
"time": "Fri, 22 Apr 2016 13:08:10 GMT",
"timesecs": 1461330490
},
"connecting_to": {
"host": "10.8.0.2",
"port": 5201
},
"cookie": "sid-Vostro-3700.1461330486.892347.18",
"test_start": {
"protocol": "UDP",
"num_streams": 1,
"blksize": 8192,
"omit": 0,
"duration": 2,
"bytes": 0,
"blocks": 0,
"reverse": 0
}
},
"intervals": [{
"streams": [{
"socket": 5,
"start": 0,
"end": 2.0002,
"seconds": 2.0002,
"bytes": 253952,
"bits_per_second": 1.01571e+06,
"packets": 31,
"omitted": false
}],
"sum": {
"start": 0,
"end": 2.0002,
"seconds": 2.0002,
"bytes": 253952,
"bits_per_second": 1.01571e+06,
"packets": 31,
"omitted": false
}
}],
"end": {
"streams": [{
"udp": {
"socket": 5,
"start": 0,
"end": 2.0002,
"seconds": 2.0002,
"bytes": 253952,
"bits_per_second": 1.01571e+06,
"jitter_ms": 828.078,
"lost_packets": 0,
"packets": 24,
"lost_percent": 0,
"out_of_order": 0
}
}],
"sum": {
"start": 0,
"end": 2.0002,
"seconds": 2.0002,
"bytes": 253952,
"bits_per_second": 1.01571e+06,
"jitter_ms": 828.078,
"lost_packets": 0,
"packets": 24,
"lost_percent": 0
},
"cpu_utilization_percent": {
"host_total": 7.7914,
"host_user": 1.09745,
"host_system": 6.69392,
"remote_total": 0,
"remote_user": 0,
"remote_system": 0
}
},
"test": 0
}
But when i try to filter the end object, my command fails.
$cat ipres.txt | jq .end
error: syntax error, unexpected end, expecting $end
.end
^^^
1 compile error
If i change the end object to some other name for example end1, i can able to filter. What could be the problem?
It would seem that you are after:
jq '.end' ipres.txt
If you are still getting the same erroneous output - then you may be using an older / badly built version of jq.
You are evidently using an early version of jq -- perhaps jq 1.3, which is well out-of-date and which has some limitations with respect to the abbreviated syntax: .foo.
That is, you would have to write .["end"] in jq 1.3, since "end" is a keyword (as in: if ... then ... else ... end).
In jq 1.4 and jq 1.5, one can write .end

jq: Getting two levels of keys

I have some json data that looks like:
{
"p": {
"d": {
"a" : {
"r": "foo",
"g": 1
},
"b": {
"r": "bar",
"g": 2
}
},
"c": {
"e": {
"r": "baz",
"g": 1
}
},
...
}
}
I want something like:
{
"d": [
"a",
"b"
],
"c": [
"e"
]
}
I can get the list of keys on the first level under "p" with jq '.p|keys', and the structure and keys on the second level with jq '.p|map(.|keys)', but I can't figure out how to combine it.
Use map_values instead of map to map the values of a JSON object while preserving the keys:
jq '.p | map_values(keys)'
On jq versions lower than 1.5, map_values is not defined: instead, you can use []|=:
jq '.p | . []|= keys'
In general
Top level keys:
curl -s https://crates.io/api/v1/crates/atty | jq '. |= keys'
[
"categories",
"crate",
"keywords",
"versions"
]
Two levels of keys:
curl -s https://crates.io/api/v1/crates/atty | jq '.| map_values(keys)'
{
"crate": [
"badges",
"categories",
"created_at",
"description",
"documentation",
"downloads",
"exact_match",
"homepage",
"id",
"keywords",
"links",
"max_version",
"name",
"newest_version",
"recent_downloads",
"repository",
"updated_at",
"versions"
],
"versions": [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16
],
"keywords": [
0,
1,
2
],
"categories": []
}
Method versions
topLevelJsonKeys() {
curl -s $1 | jq '. |= keys'
# EXAMPLE:
# topLevelJsonKeys https://crates.io/api/v1/crates/atty
}
topLevelJsonKeys2() {
curl -s $1 | jq '.| map_values(keys)'
# EXAMPLE:
# topLevelJsonKeys2 https://crates.io/api/v1/crates/atty
}
Here is a solution which uses reduce and setpath
.p
| reduce keys[] as $k (
.
; setpath([$k]; .[$k] | keys)
)

Resources