Suupose I have run the below using redis-cli.
hmset locations bangalore: '{lat: "10.32", lng: "20.10"}',
chennai: '{lat: "10.32", lng: "20.10"}',
hyderabad: '{lat: "10.20", lng: "32.21"}'
I can query bangalore data through redis-cli -
hget locations bangalore
How do I do the same through node?
I tried below but it returned undefined
client.hget("location:bangalore", function (err, obj) {
console.dir(obj);
});
I haven't worked with node, but you tried to use hget to fetch the key location:bangalore and you didn't tell it which field from the hash.
HGET is used to fetch a field inside the hash, you need to tell which field from which hash.
I imagine it goes something like this:
client.hget("locations", "bangalore", function (err, obj) {
console.dir(obj);
});
where locations is a key, and bangalore is a field inside the locations hash.
Related
I'm just learning FaunaDB and FQL and having some trouble (mainly because I come from MySQL). I can successfully query a table (eg: users) and fetch a specific user. This user has a property users.expiry_date which is a faunadb Time() type.
What I would like to do is know if this date has expired by using the function LT(Now(), users.expiry_date), but I don't know how to create this query. Do I have to create an Index first?
So in short, just fetching one of the users documents gets me this:
{
id: 1,
username: 'test',
expiry_date: Time("2022-01-10T16:01:47.394Z")
}
But I would like to get this:
{
id: 1,
username: 'test',
expiry_date: Time("2022-01-10T16:01:47.394Z"),
has_expired: true,
}
I have this FQL query now (ignore oauthInfo):
Query(
Let(
{
oauthInfo: Select(['data'], Get(Ref(Collection('user_oauth_info'), refId))),
user: Select(['data'], Get(Select(['user_id'], Var('oauthInfo'))))
},
Merge({ oauthInfo: Var('oauthInfo') }, { user: Var('user') })
)
)
How would I do the equivalent of the mySQL query SELECT users.*, IF(users.expiry_date < NOW(), 1, 0) as is_expired FROM users in FQL?
Your use of Let and Merge show that you are thinking about FQL in a good way. These are functions that can go a long way to making your queries more organized and readable!
I will start with some notes, but they will be relevant to the final answer, so please stick with me.
The Query function
https://docs.fauna.com/fauna/current/api/fql/functions/query
First, you should not need to wrap anything in the Query function, here. Query is necessary for defining functions in FQL that will be run later, for example, in the User-Defined Function body. You will always see it as Query(Lambda(...)).
Fauna IDs
https://docs.fauna.com/fauna/current/learn/understanding/documents
Remember that Fauna assigns unique IDs for every Document for you. When I see fields named id, that is a bit of a red flag, so I want to highlight that. There are plenty of reasons that you might store some business-ID in a Document, but be sure that you need it.
Getting an ID
A Document in Fauna is shaped like:
{
ref: Ref(Collection("users"), "101"), // <-- "id" is 101
ts: 1641508095450000,
data: { /* ... */ }
}
In the JS driver you can use this id by using documentResult.ref.id (other drivers can do this in similar ways)
You can access the ID directly in FQL as well. You use the Select function.
Let(
{
user: Get(Select(['user_id'], Var('oauthInfo')))
id: Select(["ref", "id"], Var("user"))
},
Var("id")
)
More about the Select function.
https://docs.fauna.com/fauna/current/api/fql/functions/select
You are already using Select and that's the function you are looking for. It's what you use to grab any piece of an object or array.
Here's a contrived example that gets the zip code for the 3rd user in the Collection:
Let(
{
page: Paginate(Documents(Collection("user")),
},
Select(["data", 2, "data", "address", "zip"], Var("user"))
)
Bring it together
That said, your Let function is a great start. Let's break things down into smaller steps.
Let(
{
oauthInfo_ref: Ref(Collection('user_oauth_info'), refId)
oauthInfo_doc: Get(Var("oathInfoRef")),
// make sure that user_oath_info.user_id is a full Ref, not just a number
user_ref: Select(["data", "user_id"], Var("oauthInfo_doc"))
user_doc: Get(Var("user_ref")),
user_id: Select("id", Var("user_ref")),
// calculate expired
expiry_date: Select(["data", "expiry_date"], Var("user_doc")),
has_expired: LT(Now(), Var("expiry_date"))
},
// if the data does not overlap, Merge is not required.
// you can build plain objects in FQL
{
oauthInfo: Var("oauthInfo_doc"), // entire Document
user: Var("user_doc"), // entire Document
has_expired: Var("has_expired") // an extra field
}
)
Instead of returning the auth info and user as separate points if you do want to Merge them and/or add additional fields, then feel free to do that
// ...
Merge(
Select("data", Var("user_doc")), // just the data
{
user_id: Var("user_id"), // added field
has_expired: Var("has_expired") // added field
}
)
)
FaunaDB's documentation covers how to update a document, but their example assumes that I'll have the id to pass into Ref:
Ref(schema_ref, id)
client.query(
q.Update(
q.Ref(q.Collection('posts'), '192903209792046592'),
{ data: { text: "Example" },
)
)
However, I'm wondering if it's possible to update a document without knowing its id. For instance, if I have a collection of users, can I find a user by their email, and then update their record? I've tried this, but Fauna returns a 400 (Database Ref expected, String provided):
client
.query(
q.Update(
q.Match(
q.Index("users_by_email", "me#example.com")
),
{ name: "Em" }
)
)
Although Bens comments are correct, (that's the way you do it), I wanted to note that the error you are receiving is because you are missing a bracket here: "users_by_email"), "me#example.com"
The error is logical if you know that Index takes an optional database reference as second argument.
To clarify what Ben said:
If you do this you'll get another error:
Update(
Match(
Index("accounts_by_email"), "test#test.com"
),
{ data: { email: "test2#test.com"} }
)
Since Match could potentially return more then one element. It returns a set of references called a SetRef. Think of setrefs as lists that are not materialized yet. If you are certain there is only one match for that e-mail (e.g. if you set a uniqueness constraint) you can materialize it using Paginate or Get:
Get:
Update(
Select(['ref'], Get(Match(
Index("accounts_by_email"), "test#test.com"
))),
{ data: { email: 'test2#test.com'} }
)
The Get returns the complete document, we need to specify that we require the ref with Select(['ref']..
Paginate:
Update(
Select(['data', 0],
Paginate(Match(
Index("accounts_by_email"), "test#test.com"
))
),
{ data: { email: "testchanged#test.com"} }
)
You are very close! Update does require a ref. You can get one via your index though. Assuming your index has a default values setting (i.e. paging a match returns a page of refs) and you are confident that the there is a single match or the first match is the one you want then you can do Select(["ref"], Get(Match(Index("users_by_email"), "me#example.com"))) to transform your set ref to a document ref. This can then be passed into update (or to any other function that wants a document ref, like Delete).
I have a redis store that I'm setting up. I want the value for each insertion to be a sorted set. Within that sorted set, I want the values to be hashes. Would that be possible? Here is my data I want to place as a json representation:
{
"siliconvalley": {
"search-list": [
{
"id": "1234",
"content-type": "VIDEO"
},
{
"id": "456",
"content-type": "SHOW"
}
]
}
}
To do a quick test in the redis cli, I attempted to do this:
//first creating a hashes key-value
HSET searchResult id "123"
//next creating my sorted set
ZADD siliconvalley 1 searchResult
however, that looks like it only stores a string in my set as "searchResult" and doesn't actually use the HSET I created
Redis is a plain key-value store, it does't handle structured data. You can't store a hash inside a set. You need to use a document based database for this like mongo or couchdb.
What you can do in Redis is use a hash who's key is siliconvalley:[searchIndexId] and a sorted set searchIndex containing just ids as an index.
HSET searchResult:123 id "123"
HSET searchResult:123 content-type "VIDEO"
ZADD searchIndex 123
HSET searchResult:456 id "456"
HSET searchResult:456 content-type "SHOW"
ZADD searchIndex 456
Now you can fetch the id from searchIndex and use this id to fetch the value of the corresponding hash.
Does this function duplicate results as a bug or am I causing this? The output always has 1 or more records duplicated. In this example, Bank of China is always listed twice in output.
gun.get('savings_accounts').map(function (name, ID) {
console.log( name.name, ID );
}, true)
My code:
localStorage.clear();
var gun = Gun();
////////////////////////////////////////////////////// create record
var acc1 = gun.put({
name: "Bank of America",
accType: "Savings",
last4: "4123",
favorite: true,
status: true,
created: "some date created"
});
var acc2 = gun.put({
name: "Bank of China",
accType: "Savings",
last4: "5123",
favorite: true,
status: true,
created: "some date created"
});
gun.get('savings_accounts').map(function (name, ID) {
console.log( name.name, ID );
}, true)
From the author of GunDB, Mark Nadal
1) gun.get('savings_accounts').map().val(cb) is what you want for normal / procedural / easy things.
HOWEVER...
2) gun is actually functional/reactive (FRP), or also known as streaming/event oriented. The data might/will get called multiple times (if you don't use .val) because A) in-memory replies, B) your browser's localStorage replies, C) the server will reply, D) server will relay to other browser peers which each might reply with data.
^ that is the "realtime" part of gun.
.val only fires once (well per item on the chain, so if you do map().val(cb) the val will get fired multiple times but only once from each item in the list).
use .val(cb) if you are doing procedural things.
Use .on(cb) (which is what .map(cb) uses internally. Most API methods internally use .on) if you want to subscribe to realtime updates of the data.
you'll slowly find that the realtime/FRP/event/streaming as being a much cleaner way to write your apps.
with CouchDB is possible do queries "like" SQL. http://guide.couchdb.org/draft/cookbook.html says that
How you would do this in SQL:
SELECT field FROM table WHERE value="searchterm"
How you can do this in CouchDB:
Use case: get a result (which can be a record or set of records) associated with a key ("searchterm").
To look something up quickly, regardless of the storage mechanism, an index is needed. An index is a data structure optimized for quick search and retrieval. CouchDB’s map result is stored in such an index, which happens to be a B+ tree.
To look up a value by "searchterm", we need to put all values into the key of a view. All we need is a simple map function:
function(doc) {
if(doc.value) {
emit(doc.value, null);
}
}
This creates a list of documents that have a value field sorted by the data in the value field. To find all the records that match "searchterm", we query the view and specify the search term as a query parameter:
/database/_design/application/_view/viewname?key="searchterm"
how can I do this with PouchDB? the API provide methods to create temp view, but how I can personalize the get request with key="searchterm"?
You just add your attribute settings to the options object:
var searchterm = "boop";
db.query({map: function(doc) {
if(doc.value) {
emit(doc.value, null);
}
}, { key: searchterm }, function(err, res) { ... });
see http://pouchdb.com/api.html#query_database for more info
using regex
import PouchDB from 'pouchdb';
import PouchDBFind from 'pouchdb-find';
...
PouchDB.plugin(PouchDBFind)
const db = new PouchDB(dbName);
db.createIndex({index: {fields: ['description']}})
....
const {docs, warning} = await db.find({selector: { description: { $regex: /OVO/}}})