How to match nested values in RethinkDB? - python-2.7

I use Python client driver and the structure of my documents is :
{"key1": ["value1"], "key2": ["value2"], ..., "key7": ["value7"]}
let say "value7" is "In every time in every place, deeds of men remain the same"
I'd like to retrieve all documents that contain "deed" for key7.
I tried
r.db('db')
.table('table')
.filter(lambda row: row['key7'].match('^deed'))
.run(conn)
but it doesn't work... I have the follwing message :
rethinkdb.errors.ReqlQueryLogicError: Expected type STRING but found
ARRAY

Here is the solution :
r.db('db')
.table('table')
.filter(lambda row: row['key7'].nth(0).match('^deed'))
.run(conn)

Related

regex to convert key values in a column to an hstore or jsonb column?

I have a database that has a table called activity with a column called detail that has this unfortunate representation of key/value pairs:
Key ID=[813],\n
Key Name=[Name of Key],\n
Some Field=[2732],\n
Another Field=[2751],\n
Description=[A text string here],\n
Location=[sometext],\n
Other ID=[2360578],\n
It's maybe clear from the formatting above, this is a one value per line and \n is a newline character so there's always one extra newline. I'm trying to avoid having an external program process this data, so I'm looking into postgresql's regex functions. The goal is to convert this to a jsonb or hstore column, I don't really care which.
Schema for the table is like:
CREATE TABLE activity
(
id integer NOT NULL,
activity_type integer NOT NULL,
ts timestamp with time zone,
detail text NOT NULL,
details_hstore hstore,
details_jsonb jsonb,
CONSTRAINT activity_pkey PRIMARY KEY (id),
);
So I'd like to run an UPDATE where I update the details_jsonb or details_hstore with the processed data from detail.
This:
select regexp_matches(activity.detail, '(.*?)=\[(.*?)\]\,[\r|\n]', 'g') as val from activity
gets me these individual rows (this is from pgadmin, I assume these are all strings):
{"Key ID",813}
{"Key Name","Name of Key"}
{"Some Field",2732}
{"Another Field",2751}
{Description,"A text string here"}
{Location,sometext}
{"Other ID",2360578}
I'm not a regex whiz but I think I need some kind of grouping. Also, that's returning as a text array of some kind, but what I really want is like this for jsonb
{"Key ID": "813", "Key Name": "Name of Key"}
or even better, if it's a number only then
{"Key ID": 813, "Key Name": "Name of Key"}
and/or the equivalent for hstore.
I feel like I'm a number of regex-in-postgres concepts away from this goal.
First is how to get ALL the pairs together in some kind of array or something, not as separate rows.
Second is, can I figure if it's a number and optionally get "" around strings and nothing around numbers for jsonb or hstore
Third, get that as some kind of string/text
Fourth is, how to then write that into another jsonb/hstore field using an update
Is this kind of regex update too much to get working in an update? i.e. update activity set details_jsonb = [[insane regex here]]? hstore is also an option (though I like that jsonb has types), so if it's easier to go to an hstore function like hstore(text[]) that's fine too.
Am I crazy and do I need to just write an external process not-in-postgresql that does this?
I would first split the single value into multiple lines. Each line can then be converted to an array from which this can be aggregated into a JSON object:
select string_to_array(regexp_replace(t.line, '(^\s+)|(\s+$)', '', 'g'), '=')
from activity a, regexp_split_to_table(a.detail, ',\s*\n') t (line)
This returns the following:
element
------------------------------------
{KeyID,[813]}
{"Key Name","[Name of Key]"}
{"Some Field",[2732]}
{"Another Field",[2751]}
{Description,"[A text string here]"}
{Location,[sometext]}
{"Other ID",[2360578]}
{}
The regex to split the detail value into lines might need some improvements though.
The regexp_replace(t.line, '(^\s+)|(\s+$)', '', 'g') is there trim the values before converting them to an array.
Now this can be aggregated into a single JSON value, or each line can be converted into a single hstore value (unfortunately there is no hstore_agg())
with activity (detail) as (
values (
'Key ID=[813],
Key Name=[Name of Key],
Some Field=[2732],
Another Field=[2751],
Description=[A text string here],
Location=[sometext],
Other ID=[2360578],
')
), elements (element) as (
select string_to_array(regexp_replace(t.line, '\s', ''), '=')
from activity a, regexp_split_to_table(a.detail, ',') t (line)
)
select json_agg(jsonb_object(element))
from elements
where cardinality(element) > 1 -- this removes the empty line
The above returns a JSON object:
[ { "KeyID" : "[813]" },
{ "Key Name" : "[Name of Key]" },
{ "Some Field" : "[2732]" },
{ "Another Field" : "[2751]" },
{ "Description" : "[A text string here]" },
{ "Location" : "[sometext]" },
{ "Other ID" : "[2360578]" }
]

Where condition in geode

I am new to geode .
I am adding like below:
gfsh>put --key=('id':'11') --value=('firstname':'Amaresh','lastname':'Dhal') --region=region
Result : true
Key Class : java.lang.String
Key : ('id':'11')
Value Class : java.lang.String
Old Value : <NULL>
when I query like this:
gfsh>query --query="select * from /region"
Result : true
startCount : 0
endCount : 20
Rows : 9
Result
-----------------------------------------
('firstname':'A2','lastname':'D2')
HI
Amaresh
Amaresh
('firstname':'A1','lastname':'D1')
World
World
('firstname':'Amaresh','lastname':'Dhal')
Hello
NEXT_STEP_NAME : END
When I am trying to query like below I am not getting the value:
gfsh>query --query="select * from /region r where r.id='11'"
Result : true
startCount : 0
endCount : 20
Rows : 0
NEXT_STEP_NAME : END
Ofcourse I can use get command...But i want to use where condition..Where I am doing wrong..It gives no output
Thanks
In Geode the key is not "just another column". In fact, the basic query syntax implicitly queries only the fields of the value. However, you can include the key in your query using this syntax:
select value.lastname, value.firstname from /region.entries where key.id=11
Also, it is fairly common practice to include the id field in your value class even though it is not strictly required.
What Randy said is exactly right, the 'key" is not another column. The exact format of the query should be
gfsh>query --query="select * from /Address.entries where key=2"
What you are looking for here is getting all the "entries" on the region "Address" and then querying the key.
To check which one you want to query you can fire this query
gfsh>query --query="select * from /Address.entries"
You can always use the get command to fetch the data pertaining to a specific key.
get --key=<KEY_NAME> --region=<REGION_NAME>
Example:
get --key=1 --region=Address
Reference: https://gemfire.docs.pivotal.io/910/geode/tools_modules/gfsh/command-pages/get.html

mongodb - perform subquery

a document:
{ "_id":1, "id":1, "list" : [ { "lv" : 1 , "id":1}, {"lv" : 2 , "id":2} ] }
I want do find({"_id":1},{"id":1, "list.lv":1}) but limit {"list.lv":1} with an additional condition: "list.id = id". That means I only want to retrieve "id" and the "list.lv" part of the first element in list because its "list.id" == "id" == 1
Normally the condition value provided in code, but in this example, the value is in the document. SQL do this by subquery or join table. Does mongodb support this in a single query? And how to write it in c++ driver?
According to answer, add c++ code:
mongo::BSONObj res;
std::vector<mongo::BSONObj> pipeline;
pipeline.push_back(BSON("$match"<<BSON("_id"<<1)));
pipeline.push_back(BSON("$unwind"<<"$list"));
mongo::BSONArrayBuilder ab;
ab<<"$id"<<"$list.id";
pipeline.push_back(BSON("$project"<<BSON("id"<<1<<"list.lv"<<1<<"equalsFlag"<<BSON("$subtract"<<ab.arr()))));
pipeline.push_back(BSON("$match"<<BSON("equalsFlag"<<0)));
pipeline.push_back(BSON("$project"<<BSON("id"<<1<<"list.lv"<<1)));
conn->runCommand("db_name", BSON( "aggregate" << "collection_name" << "pipeline" << pipeline ), res);
std::cout<<res["result"].Array()[0].Obj().getObjectField("list").getIntField("lv");
If I got you question try this native aggregate framework query to accomplish what you need:
db.collectionName.aggregate(
{"$match" : {"_id" : 1 }},
{"$unwind" : "$list"},
{"$project" : {"id":1, "list.lv" : 1, "equalsFlag" : {"$subtract" : ["$id", "$list.id"]}}},
{"$match" : {"equalsFlag" : 0}},
{"$project" : {"id": 1, "list.lv" : 1}})
Let me explain it in more detail. It's important to filter out as much documents as we can at first. We can do it with the first $match. Note that if we do {"_id" : 1 } filter at the end of the pipeline mongo will not be able to use index for it. $unwind will turn each list array element into a seperate document. Then we need to compare two fields. I'm not aware of any easy way to do it except for $where but we cant use it with aggregate framework. Fortunately both id and list.id are numeric so we can $subtract one from another to see if they are equal, "equalsFlag" : {"$subtract" : ["$id", "$list.id"]} . If they are, equalsFlag will be 0. So we just add a new $match to get documents where id=list.id and finally to omit equalsFlag field from results we have one more $project.
I'm not a C++ guy but I'm sure C++ driver supports aggregate framework as most of other drivers. So just google some examples to convert this native query into a C++ one. This should be fairly easy at least it's true for C#.
EDIT: C++ code from jean to complete the answer
mongo::BSONObj res;
std::vector<mongo::BSONObj> pipeline;
pipeline.push_back(BSON("$match"<<BSON("_id"<<1)));
pipeline.push_back(BSON("$unwind"<<"$list"));
mongo::BSONArrayBuilder ab;
ab<<"$id"<<"$list.id";
pipeline.push_back(BSON("$project"<<BSON("id"<<1<<"list.lv"<<1<<"equalsFlag"<<BSON("$subtract"<<ab.arr()))));
pipeline.push_back(BSON("$match"<<BSON("equalsFlag"<<0)));
pipeline.push_back(BSON("$project"<<BSON("id"<<1<<"list.lv"<<1)));
conn->runCommand("db_name", BSON( "aggregate" << "collection_name" << "pipeline" << pipeline ), res);
std::cout<<res["result"].Array()[0].Obj().getObjectField("list").getIntField("lv");
Hope it helps!

How to display a list in django tables 2

I have a list containing some objects that i want to display in django tables 2 but as a result i got the - in all the columns.
My list is like this format [[<Person>],[<Person>]]
Reading the documentation I've found that this format works :
data = [
{"name": "Bradley"},
{"name": "Stevie"},
]
How can I get a format like this knowing that my data is dynamic?
Update :
I tried this :
for x in person_list:
for y in x:
data=[
{"firstname": y.firstname},
{"surname":y.surname},
]
The problem is now it displays every field in a row, I mean first name in row and surname in another one. How to append to the same data ?
Try to produce your data table manually
I suppose person has first_name field
data=[{"name": x.first_name} for x in persons_list]
Ok so I found the solution to this inspired by this :
d={}
dlist=[]
for x in person_list:
for y in x:
d['firstname']=y.firstname
d['lastname']=y.lastname
dlist.append(d)
And it works like a charm !

How to query MongoDB for matching documents where item is in document array

If my stored document looks like this:
doc = {
'Things' : [ 'one' , 'two' , 'three' ]
}
How can I query for documents which contain one in Things?
I know the $in operator queries a document item against a list, but this is kind of the reverse. Any help would be awesome.
Use MongoDB's multikeys support:
MongoDB provides an interesting "multikey" feature that can automatically index arrays of an object's values.
[...]
db.articles.find( { tags: 'april' } )
{"name" : "Warm Weather" , "author" : "Steve" ,
"tags" : ["weather","hot","record","april"] ,
"_id" : "497ce4051ca9ca6d3efca323"}
Basically, you don't have to worry about the array-ness of Things, MongoDB will take care of that for you; something like this in the MongoDB shell would work:
db.your_collection.find({ Things: 'one' })