I have data in clojure defined as:
(def data {:actor "damas.nugroho"
:current-attributes [{:key "name", :value "adam"}
{:key "city", :value "jakarta"}]})
and I want to get the city value which means jakarta. How can I do that?
This is the data you have:
(def data
{:actor "damas.nugroho"
:current-attributes [{:key "name", :value "adam"}
{:key "city", :value "jakarta"}]})
And this is how you get at the city:
(->> (:current-attributes data)
(some #(when (= (:key %) "city")
(:value %))))
But the value of :current-attributes seems like a map, by essence. Assuming the keys don't repeat, consider transforming it into a map for easier manipulation.
(def my-new-data
(update data :current-attributes
#(into {} (map (juxt :key :value)) %)))
my-new-data will end up becoming this:
{:actor "damas.nugroho"
:current-attributes {"name" "adam"
"city" "jakarta"}}
Getting the city is then just a nested map lookup, and can be done with (get-in my-new-data [:current-attributes "city"])
Also, :current-attributes is not specific and unless it may contain :actor as a key, or has a particular meaning you care about in some context, can be flattened.
Also, assuming the names of the keys in current-attributes are programmatic names, and follow the syntax of keywords in Clojure, you could convert them to keywords, and pour them all into a map:
(def my-newer-data
(let [attrs (into data
(map (juxt (comp keyword :key) :value))
(:current-attributes data))]
(dissoc attrs :current-attributes)))
Now we end up with this:
{:actor "damas.nugroho", :name "adam", :city "jakarta"}
And extracting city is just saying it, (:city my-newer-data)
Related
I am new to Clojure and I am trying to iterate over a PersistentVector of objects, which looks like below when I print in logs.
[{name John, email john#example.com} {name Peter, email peter#example.com}]
when I print (type myData) it tells me it is of type clojure.lang.PersistentVector
I have to iterate over this vector, extract email from each object inside it at a time and invoke another function.
It looks very simple, I looked at many samples and questions, but nothing seem to work for me :(
Thanks.
Here are a couple of options:
If you don't care about the objects ("maps" in Clojure speak) and only want to collect the emails and apply a function over them, you can create a simple function just to extract the emails into another collection and then use any function over the collection of emails:
(def items
[{"name" "John", "email" "john#example.com"} {"name" "Peter", "email" "peter#example.com"}])
(defn get-email [m]
(get m "email"))
(mapv get-email items)
;; returns: ["john#example.com", "peter#example.com"]
You can use function composition to the create a function that turns into upper case (using upper-case from clojure.string) the result of getting the email: (note the ordering in comp):
(mapv (comp clojure.string/upper-case get-email) items)
;; returns ["JOHN#EXAMPLE.COM" "PETER#EXAMPLE.COM"]
If you want to obtain a similar collection but with the email field updated, you can use update-in:
(mapv (fn [m] (update-in m ["email"] clojure.string/upper-case)) items)
;; Applies `upper-case` to the "email" path of each map identified by `m`.
;; returns: [{"name" "John", "email" "JOHN#EXAMPLE.COM"} {"name" "Peter", "email" "PETER#EXAMPLE.COM"}]
There are more elegant ways to do the same work using other techniques (anonymous functions, strs destructuring) but I think the ones above are simpler to understand if you are new to Clojure.
I was wondering if the Filters in Keen IO queries can be done as "OR".
Basically, I have a "column" (event property) called "product_type".
I want to generate an API Query URL that has an extraction with a filter that is "if product_type equals x OR product_type equals y".
But right now, if I do a Filter like that, it's always "AND".
Use the the "in" operator. This "in" operator will identify any events where the property equals any value in a list, like this:
var extraction = new Keen.Query("extraction", {
event_collection: "purchases",
timeframe: "this_14_days",
filters: [
{
property_name: "product_type",
operator: "in",
property_value: ["x","y"]
}
]
});
Here's a handy list of all of the available filter operators.
I'm using this JSON parser to extract data from a JSON response I'm getting from an API. It returns a byte array containing the data and when convert the byte array to a string and print it, I get the following output:
[{"Name": "Vikings", "Type": "show"},
{"Name": "Spartacus: Gods Of The Arena", "Type": "show"},
{"Name": "True Detective", "Type": "show"},
{"Name": "The Borgias", "Type": "show"},
{"Name": "Se7en", "Type": "movie"}]
Since this is a regular string, I have no way of maniuplating the data to extract whatever I need. Ideally, I'd like to have arrays like these:
shows := ["Vikings", "Spartacus: Gods Of The Arena"...]
movies := ["Se7en", "other data", ...]
What I want to do with these arrays is give the user titles based on the type (ie: show, movie, etc) he/she asked for. So essentially what I'm looking for is a way to convert the string in to something that I can easily manipulate (and possibly filter).
I apoligize if this seems like a strange way of doing this, but I can't think of any other way of doing it. I feel like Go's syntax and way of doing things is very unconventional compared to another language like Javascript where I could easily have done this in a line or two.
Use the standard encoding/json package to unmarshal the data into a value matching the shape of the data:
var items []struct { // Use slice for JSON array, struct for JSON object
Name string
Type string
}
if err := json.Unmarshal(d, &items); err != nil {
log.Fatal(err)
}
Loop through the unmarshaled items to find shows and movies:
var shows, movies []string
for _, item := range items {
switch item.Type {
case "movie":
movies = append(movies, item.Name)
case "show":
shows = append(shows, item.Name)
}
}
playground example
What is the most efficient way to break down this CREATE cypher query?
The end pattern is the following:
(newTerm:term)-[:HAS_META]->(metaNode:termMeta)
In this pattern this is a single newTerm node and about ~25 termMeta nodes. The HAS_META relationship will have a single property (languageCode) that will be different for each termMeta node.
In the application, all of these nodes and relationships will be created at the same time. I'm trying to determine the best way to add them.
Is there anyway to add these without having to have perform individual query for each TermMeta node?
I know you can add multiple instances of a node using the following query format:
"metaProps" : [
{"languageCode" : "en", "name" : "1", "dateAdded": "someDate1"},
{"languageCode" : "de", "name" : "2", "dateAdded": "someDate2"},
{"languageCode" : "es", "name" : "3", "dateAdded": "someDate3"},
{"languageCode" : "fr", "name" : "3", "dateAdded": "someDate4"}
]
But you can only do that for one type of node at a time and there (as far as I can tell) is no way to dynamically add the relationship properties that are needed.
Any insight would be appreciated.
There's no really elegant way to do it, as far as I can tell—from your example, I'm assuming you're using parameters. You can use a foreach to loop through the params and do a create on each one, but it's pretty ugly, and requires you to explicitly specify literal maps of your properties. Here's what it would look like for your example:
CREATE (newTerm:term)
FOREACH ( props IN {metaProps} |
CREATE newTerm-[:HAS_META {languageCode: props.languageCode}]->
(:termMeta {name: props.name, dateAdded: props.dateAdded})
)
WITH newTerm
MATCH newTerm-[rel:HAS_META]->(metaNode:termMeta)
RETURN newTerm, rel, metaNode
If you don't need to return the results, you can delete everything after the FOREACH.
Select and name each vertex differently and then create relations using it.
For ex
match (n:Tag), (m:Account), (l:FOO) CREATE (n)-[r:mn]->(m),(m)-[x:ml]->(l)
match (n:Tag{a:"a"}), (m:Account{b:"x"}), (l:FOO) CREATE (n)-[r:mn]->(m),(m)-[x:ml]->(l)
I am putting entities (as a datastore.PropertyList) into the datastore like this:
// save one
var plist datastore.PropertyList = make(datastore.PropertyList, 3)
plist = append(plist, datastore.Property { "name", "Mat", false, false })
plist = append(plist, datastore.Property { "age", "29", false, false })
plist = append(plist, datastore.Property { "location", "London", false, false })
key := datastore.NewIncompleteKey(context, "Record", nil)
datastore.Put(context, key, &plist)
// save another one
var plist datastore.PropertyList = make(datastore.PropertyList, 3)
plist = append(plist, datastore.Property { "name", "Laurie", false, false })
plist = append(plist, datastore.Property { "age", "27", false, false })
plist = append(plist, datastore.Property { "location", "London", false, false })
key := datastore.NewIncompleteKey(context, "Record", nil)
datastore.Put(context, key, &plist)
That all works fine (although the code above is more like pseudo code for now). I am able to load them individually, and the datastore.PropertyList comes out with each field as its own datastore.Property.
However, when I try to retrieve many of them using a Query, it fails:
query := datastore.NewQuery("Record")
plists := make(datastore.PropertyList, 0, 10)
keys, err := query.GetAll(context, &plists)
I get the following error:
datastore: cannot load field "age" into a "datastore.Property": no such struct field
It seems that it doesn't complain about Name because that happens to be a valid property of datastore.Property, so how do I get it to load the items as intended, with each item in plists being a datastore.PropertyList instead of datastore.Property?
I changed the implementation to use the PropertyLoadSaver interface - you can see it working nicely in our new Active Record style wrapper for datastore: http://github.com/matryer/gae-records (see the record.go type's Load and Save methods)
Try writing your field names with a capital letter, for example, instead of age, write Age. This tells Go that your field is exported (it's similar to the concept of public variables, though it goes a bit further than that).
According to the Go datastore documentation (look at the Get method in the Functions section), a Get or GetAll method call, will return an ErrFieldMismatch "when a field is to be loaded into a different type than the one it was stored from, or when a field is missing or unexported in the destination struct. ErrFieldMismatch is only returned if dst is a struct pointer.". My best guess is that since you stored it as a PropertyList with unexported names, and since the datastore is flexible in its models, it will take the original values as unexported, due to their lowercase letters.
I am currently having the same error, but I managed to track it down to being due to some empty fields.
If this solves your problem, please let me know.
GetAll runs the query in the given context and returns all keys that match that query, as well as appending the values to dst. The dst must be a pointer to a slice of structs, struct pointers, or Maps. If q is a “keys-only” query, GetAll ignores dst and only returns the keys.
And according to the following post the go datastore module doesn't support PropertyList yet.
Use a pointer to a slice of datastore.Map instead.
Also note that you need to do call make([]T, n) in order to make a slice of T, not make(T, n)