Storing JSON in Redis where several data items are optional - javascript

I need to store the data in Redis in the following structure.
{
"userId":1,
"latitude":44.24,
"longitude":-100.24,
"items": [
{
"name":"Rollerball Pen",
"attributes":[
{"Weight":"10 grams"},
{"Manufacturer":"Luxor"}
]
},
{
"name":"Measuring Tape"
}
]
},
{
"userId":2,
"items": [
{
"name":"Laptop",
"attributes":[
{"Brand":"DELL"}
]
},
{
"name":"Scissor"
}
]
},
{
"userId":3,
"latitude":47.24,
"longitude":-102.37
},
{
"userId":4
}
The key is the user id, probably like this:
"user:" + userId.toString()
Note that following are optional:
a. Latitude and Longitude
b. array of items
c. array of attributes (in items)
I have tried to sum up every possible use case using the 4 different user ids.
How can I store and access this kind of data in Redis, kindly help me out. The language that I am using is JavaScript.

Related

Aggregating the result of the MongoDB model query

I have a model Book with a field "tags" which is of type array of String / GraphQLString.
Currently, I'm able to query the tags for each book.
{
books {
id
tags
}
}
and I get the result:
{
"data": {
"books": [
{
"id": "631664448cb20310bc25c89d",
"tags": [
"database",
"middle-layer"
]
},
{
"id": "6316945f8995f05ac71d3b22",
"tags": [
"relational",
"database"
]
},
]
}
}
I want to write a RootQuery where I can fetch all unique tags across all books. This is how far I am (which is not too much):
tags: {
type: new GraphQLList(GraphQLString),
resolve(parent, args) {
Book.find({}) // CAN'T FIGURE OUT WHAT TO DO HERE
return [];
}
}
Basically, I'm trying to fetch all books and then potentially merge all tags fields on each book.
I expect that if I query:
{
tags
}
I would get
["relational", "database", "middle-layer"]
I am just starting with Mongoose, MongoDB, as well as GraphQL, so not 100% sure what keywords to exactly look fo or even what the title of this question should be.
Appreciate the help.
You want to $unwind the arrays so they're flat, at that point we can just use $group to get unique values. like so:
db.collection.aggregate([
{
"$unwind": "$data.books"
},
{
"$unwind": "$data.books.tags"
},
{
$group: {
_id: "$data.books.tags"
}
}
])
Mongo Playground
MongoDb + JavaScript Solution
tags = Book.aggregate([
{
$project: {
tags: 1,
_id: 0,
}
},
])
This returns an array of objects that contain only the tags value. $project is staging this item in the aggregation pipeline by selecting keys to include, denoted by 1 or 0. _id is added by default so it needs to be explicitly excluded.
Then take the tags array that looks like this:
[
{
"tags": [
"database",
"middle-layer"
]
},
{
"tags": [
"relational",
"database"
]
}
]
And reduce it to be one unified array, then make it into a javascript Set, which will exclude duplicates by default. I convert it back to an Array at the end, if you need to perform array methods on it, or write back to the DB.
let allTags = tags.reduce((total, curr) => [...total, ...curr.tags], [])
allTags = Array.from(new Set(allTags))
const tags = [
{
"tags": [
"database",
"middle-layer"
]
},
{
"tags": [
"relational",
"database"
]
}
]
let allTags = tags.reduce((total, curr) => [...total, ...curr.tags], [])
allTags = Array.from(new Set(allTags))
console.log(allTags)
Pure MongoDB Solution
Book.aggregate([
{
$unwind: "$tags"
},
{
$group: {
_id: "_id",
tags: {
"$addToSet": "$tags"
}
}
},
{
$project: {
tags: 1,
_id: 0,
}
}
])
Steps in Aggregation Pipeline
$unwind
Creates a new Mongo Document for each tag in tags
$group
Merges the individual tags into a set called tags
Sets are required to be have unique values and will exclude duplicates by default
_id is a required field
_id will be excluded from the final aggregation so it doesn't matter what it is
$project
Chooses which fields to pull from the previous step in the pipeline
Using it here to exclude _id from the results
Output
[
{
"tags": [
"database",
"middle-layer",
"relational"
]
}
]
Mongo Playground Demo
While this solution gets the result with purely Mongo queries, the resulting output is nested and still requires traversal to get to desired fields. I do not know of a way to replace the root with a list of string values in an aggregation pipeline. So at the end of the day, JavaScript is still required.

Supabase JSON query JavaScript

Im trying to fetch single entry from my table that contains and JSONB array of objects. Can I match somehow that array to find the desired result?
[
{
"chats": [
{
"id": 56789,
},
{
"id": 66753,
},
],
"id": 999
},
{
"chats": [
{
"id": 43532,
}
],
"id": 999
}
]
I would like to get the object that matches id 999 and contains in chats -> id: 66753
Tried few approaches but none worked.
I though something link this will work.But no success
let { data, error } = await supabase
.from('xyz')
.select('*')
.eq('id', 999)
.contains('chats', {id: 66753})
Can it be done ?
I believe you need to use the ->> operator when querying JSONB data from supabase as noted here in the docs.
So, if your column with the array of objects is titled jsonb, something to the effect of:
let { data, error } = await supabase
.from('xyz')
.select('*')
.eq('id:jsonb->>id', 999)
.contains('chats:jsonb->>chats', ['chats->id: 66753'])
More info can be found on PostgREST docs here

How to get all values of given specific keys (for e.g: name) without loop from json?

I want to fetch all the names and label from JSON without loop. Is there a way to fetch with any filter method?
"sections": [
{
"id": "62ee1779",
"name": "Drinks",
"items": [
{
"id": "1902b625",
"name": "Cold Brew",
"optionSets": [
{
"id": "45f2a845-c83b-49c2-90ae-a227dfb7c513",
"label": "Choose a size",
},
{
"id": "af171c34-4ca8-4374-82bf-a418396e375c",
"label": "Additional Toppings",
},
],
},
]
}
When you say "without loops" I take it as without For Loops. because any kind of traversal of arrays, let alone nested traversal, involve iterating.
You can use the reduce method to have it done for you internally and give you the format you need.
Try this :
const data = {
sections: [
{
id: "62ee1779",
name: "Drinks",
items: [
{
id: "1902b625",
name: "Cold Brew",
optionSets: [
{
id: "45f2a845-c83b-49c2-90ae-a227dfb7c513",
label: "Choose a size"
},
{
id: "af171c34-4ca8-4374-82bf-a418396e375c",
label: "Additional Toppings"
}
]
}
]
}
]
};
x = data.sections.reduce((acc, ele) => {
acc.push(ele.name);
otherName = ele.items.reduce((acc2, elem2) => {
acc2.push(elem2.name);
label = elem2.optionSets.reduce((acc3, elem3) => {
acc3.push(elem3.label);
return acc3;
}, []);
return acc2.concat(label);
}, []);
return acc.concat(otherName);
}, []);
console.log(x);
Go ahead and press run snippet to see if this matches your desired output.
For More on info reduce method
In the context of cJSON
yes, we can fetch the key value for any of the object.
1 - each key value is pointed by one of the objects. will simply fetch that object and from there will get the key value.
In the above case for
pre-requisition: root must contain the json format and root must be the cJSON pointer. if not we can define it and use cJSON_Parse() to parse the json.
1st name object is "sections" will use
cJSON *test = cJSON_GetObjectItem(root, "sections");
char *name1 = cJSON_GetObjectItem(test, "name" )->valuestring;
2nd name key value
cJSON *test2 = cJSON_GetObjectItem(test, "items");
char *name2 = cJSON_GetObjectItem(tes2, "name")->valuestring;
likewise, we can do for others as well to fetch the key value.

Firebase Fanout Structure List Query

For the Firebase fanout data structure example of users and groups, what would be the most efficient way to retrieve user/member ("users") detail data for a given group from the "groups" list? Let's say the goal was to display the "name" property for each member of group "techpioneers"?
{
"users": {
"alovelace": {
"name": "Ada Lovelace",
"groups": {
"techpioneers": true,
"womentechmakers": true
}
},
},
"groups": {
"techpioneers": {
"name": "Historical Tech Pioneers",
"members": {
"alovelace": true,
"ghopper": true
}
},
...
}
}
Would using a combination of orderByChild() and equalTo() be the best approach to find users who have "techpioneers" key and get at each of their data such as the "name" property? How would you access a property such as "name" once you've determined which users are part of the target group?
let usersRef = firebase.database().ref('users')
usersRef.orderByChild("groups").equalTo('techpioneers').on('child_added', (snapshot) => {
// how would you access user "alovelace" name property?
console.log(snapshot.val().name);
});
Thank you for any help you can provide.

Update ReactJS state array

I have a ReactJS component that renders a list of orders.
I get orders from a REST API. The format of the data is the following:
{
"count": 2,
"orders": [
{
"order_number": 55981,
"customer_number": 24742
},
{
"order_number": 55980,
"customer_number": 24055
}
]
}
Each order can have a list of items. When I click on an order, I get the list of items in the following format:
{
"count": 2,
"items": [
{
"name": "Green pillow",
"status": "pending"
},
{
"name": "Red pillow",
"status": "delivered"
}
]
}
The orders list is refreshed automatically and can change any time, so I store the orders list in this.state which gets updated via ajax.
this.state looks like this:
{
"orders": [
{
"order_number": 55981,
"customer_number": 24742
},
{
"order_number": 55980,
"customer_number": 24055
}
]
}
My problem is that I would like that, when I click on an order, the state gets updated so that the clicked order contains the items associated to that order. The order list would look like this after clicking on an item:
{
"count": 2,
"orders": [
{
"order_number": 55981,
"customer_number": 24742,
"items": [
{
"name": "Green pillow",
"status": "pending"
}
]
},
{
"order_number": 55980,
"customer_number": 24055
}
]
}
How can I add items to a specific order using this.setState()? The problem is that setState seem to update data using keys, but my orders are in an array. I can probably copy the whole array and put the items key inside, but that seems overkill.
Am I taking the wrong approach?
I'm not entirely sure I got your question, but I think that what you're trying to achieve is add new orders to an array (push) which is located in your state.
If that's the case, you should something like this:
// since you're orders it's not a plain array, you will have
// to deep clone it (e.g. with lodash)
let orders = _.clone(this.state.orders);
orders.push(newOrder);
this.setState(orders);
Why cloning the state before changing it is important?
Immutability comes with some great properties (like easy equality comparison) and the React team is aiming towards that direction to improve performance more and more.
As of React 0.13 mutating state without calling this.setState will trigger a warning, and it will break entirely at some point in React's future (see the docs)
Hope this helps
Make a copy of the current state, modify the copy and use it as the new state.
This is just a simple example. You might want to add some caching logic so you don't have to retrieve the order's item again and again when a user click on the same order multiple times.
var updatedOrder = _.clone(this.state.orders);
updatedOrder[0]["items"] = [ { "name": "Foo", "status":"bar" } ];
this.setState({
orders: updatedOrder
});

Categories

Resources