How to get the collection based upon the wildchar redis key using redis-rb gem? - ruby

The redis objects created using the redis-rb gem.
$redis = Redis.new
$redis.sadd("work:the-first-task", 1)
$redis.sadd("work:another-task", 2)
$redis.sadd("work:yet-another-task", 3)
Is there any method to get the collection that has "work:*" keys?

Actually, if you just want to build a collection on Redis, you only need one key.
The example you provided builds 3 distinct collections, each of them with a single item. This is probably not that you wanted to do. The example could be rewritten as:
$redis = Redis.new
$redis.sadd("work","the-first-task|1")
$redis.sadd("work", "another-task|2")
$redis.sadd("work", "yet-another-task|3")
To retrieve all the items of this collection, use the following code:
x = $redis.smembers("work")
If you need to keep track of the order of the items in your collection, it would be better to use a list instead of a set.
In any case, usage of the KEYS command should be restricted to tooling/debug code only. It is not meant to be used in a real application because of its linear complexity.
If you really need to build several collections, and retrieve items from all these collections, the best way is probably to introduce a new "catalog" collection to keep track of the keys corresponding to these collections.
For instance:
$redis = Redis.new
$redis.sadd("catalog:work", "work:the-first-task" )
$redis.sadd("catalog:work", "work:another-task" )
$redis.sadd("work:the-first-task", 1)
$redis.sadd("work:the-first-task", 2)
$redis.sadd("work:another-task", 3)
$redis.sadd("work:another-task", 4)
To efficiently retrieve all the items:
keys = $redis.smembers("catalog:work")
res = $redis.pipelined do
keys.each do |x|
$redis.smembers(x)
end
end
res.flatten!(1)
The idea is to perform a first query to get the content of catalog:work, and then iterate on the result using pipelining to fetch all the data. I'm not a Ruby user, so there is probably a more idiomatic way to implement it.
Another simpler option can be used if the number of collections you want to retrieve is limited, and if you do not care about the ownership of the items (in which set is stored each item)
keys = $redis.smembers("catalog:work")
res = $redis.sunion(*keys)
Here the SUNION command is used to build a set resulting of the union of all the sets you are interested in. It also filters out the duplicates in the result (this was not done in the previous example).

Well, I could get it by $redis.keys("work:*").

Related

Get neo4j result

I'm using neo4j jdbc driver to access a local service and make the following query to find what I need:
"MATCH (u:User)-->(d:Deck)-[p:Played]->(g:Game)" +
"WHERE id(g) = ?" +
"RETURN {r {user :u, deck :d, played:p, game:g}}"
I cast it as a map and can find the parts and, right there in my face, I can see the stuff I need. How do I get it? (the {comment= ...} etc)
I do know how to get it by
RETURN p.comment, p.place ... etc
But I fear this will soon get out of hand. If I can just get at least that json string I would be happy.
There is a built-in Cypher function PROPERTIES(), outlined here, that will convert anything that has properties (nodes, relationships, even pre-existing Maps) to a Map of the properties with no other data. The language drivers have built-in tools to hydrate Nodes and Relationships so that property access is simple, but if you require a Map and only a Map to be returned, just use RETURN PROPERTIES(p) and you'll get it.
Reading between the lines, it looks like you are trying to get all the properties of specific nodes and properties, without any extraneous metadata.
After installing the APOC plugin, you can use the apoc.map.fromPairs procedure to generate a map with all the properties of a node or relationship.
For example, to get all the properties of every User node:
MATCH (u:User)
CALL apoc.map.fromPairs([k IN KEYS(u) | [k, u[k]]]) YIELD value AS props
RETURN props;
[k IN KEYS(u) | [k, u[k]]] generates a collection of key/value collections.
The apoc.map.fromPairs() procedure takes a collection of key/value collections, and converts it into a map.

If I eager load associated child records, then that means future WHERE retrievals won't dig through database again?

Just trying to understand... if at the start of some method I eager load a record and its associated children like this:
#object = Object.include(:children).where(email:"test#example.com").first
Then does that mean that if later I have to look through that object's children this will not generate more database queries?
I.e.,
#found_child = #object.children.where(type_of_child:"this type").first
Unfortunately not - using ActiveRecord::Relation methods such as where will query the database again.
You could however filter the data without any further queries, using the standard Array / Enumerable methods:
#object.children.detect {|child| child.type_of_child == "this type"}
It will generate another database query in your case.
Eager loading is used to avoid N+1 queries. This is done by loading all associated objects. But this doesn't work when you want to filter that list with where later on, Rails will than build a new query and run that one.
That said: In your example the include makes your code actually slower, because it loads associated object, but cannot use them.
I would change your example to:
#object = Object.find_by(email: "test#example.com")
#found_child = #object.children.find_by(type_of_child: "this type")

how to customize plone 4 collection to sort by multiple fields

I'm building a Plone 4.1 based site and am trying to find the best way to either sort a collection by multiple sort criteria, or at least customize a collection portlet to do so for the font page of the site. I believe the portlet uses the collection sort settings unless you choose random. Here is the section of code from the standard results in the portlet:
def _standard_results(self):
results = []
collection = self.collection()
if collection is not None:
limit = self.data.limit
if limit and limit > 0:
# pass on batching hints to the catalog
results = collection.queryCatalog(batch=True, b_size=limit)
results = results._sequence
else:
results = collection.queryCatalog()
if limit and limit > 0:
results = results[:limit]
return results
For example, I would like to be able to sort by Expiration Date if present, if not then use the Creation Date for example. Or sort by tags and Creation Date. Any feedback on the best approach to this would be appreciated.
as ross said you'll need AdvancedQuery to sort on multiple criteria.
if you just need this for the frontpage i'd suggest do create a custom portelt based on the collectionportlet.
where the collectionportlet calls collection.queryCatalog() you'll want to add some additional logic for your sorting:
>>> uids = [brain.UID for brain in collection.queryCatalog()]
>>> query = AdvancedQuery.In('UID', uids)
>>> results = catalog.evalAdvancedQuery(query, (('sortable_title', 'asc'), ('date', 'desc')
then you can use results instead of the results in your code sample above
As in this answer, multiple sort is only available through AdvancedQuery an there's no integration of AdvancedQuery into collections that I'm aware of. So basically this isn't possible unless you integrate AdvancedQuery into collections yourself, which would be a non-trivial task.
A hackish workaround might be to use plone.indexer to write an indexer that returns the right sort value according to your logic, create a new FieldIndex in the catalog (profiles/default/catalog.xml), register that new index as valid for sort criterion in profiles/default/portal_atct.xml, then use that as your sort index.

how to group objects in an array Ruby

I have an array of users who are managers.
However there are repeated Users.
I would like to group them so that there is only one instance of each User in the array.
What would be the best way to go about this?
#managers.sort_by{|obj| obj.id} # Just sorted the data but did not eliminate duplicats
#managers.group_by{|u|u.name} # just created a bunch of arrays for each name
Use the uniq method, which returns a new array with duplicates removed.
#managers.uniq
If by duplicate you mean the same object ID, then you can do the following:
#managers.uniq.group_by(&:name)
Filtering the array feels like fixing symptoms. Why does the array contain rubbish in the first place?
I would suggest adding a manager? method to your User model that returns true if the user is a manager. Then you could to something like
#managers = User.select &:manager?
and get an array that only contains managers.
you can also do
Manager.select('DISTINCT user_id')
to get a clean array in the first place, whith better performance.

Retrieve list of mongo documents by ids preserving order

Which is the best way to retrieve a list of mongodb documents using mongoid in the order specified in the list.
My current solution is:
docs = Doc.where(:_id.in => ids).sort { |x, y| ids.index(x.id) <=> ids.index(y.id) }
It seems there should be a better solution for this using mongoid query interface. Any ideas?
If the number of ids is small you might get away with this (no need to sort it though):
docs = ids.map { |id| Doc.find(id) }
The drawback is of course that it will still go to the database for every document.
The closest method I could find is Doc.criteria.for_ids(ids) but it will not honor the order of the ids and fetch every document only once. See this question.

Resources