I am using gdal-ruby to parse ESRI ShapeFiles like in this demo. I want to iterate through all features in order to push the field values into a database. However, I cannot find out how to retrieve the name of each field which I need to match the database column. By now I can only work with the field index of the field such as:
dataset = Gdal::Ogr.open(filename)
number_of_layers = dataset.get_layer_count
number_of_layers.times do |layer_index|
layer = dataset.get_layer(layer_index)
layer.get_feature_count.times do |feature_index|
feature = layer.get_feature(feature_index)
feature.get_field_count.times do |field_index|
field_value = feature.get_field(field_index)
# How can I find out the name of the field?
puts "Value = #{field_value} for unknown field name"
end
end
end
I checked the available methods with irb and looked into the API documentation. It seems as if I am searching for the wrong terms.
Looking at the OGR API itself, I think you need to go via feature.GetDefnRef, to get the feature definition, then .GetFieldDefn for the relevant field, and finally .GetNameRef...?
...
feature.get_field_count.times do |field_index|
defn_ref = feature.get_defn_ref
field_defn = defn_ref.get_field_defn(field_index)
field_name = field_defn.get_name
field_value = feature.get_field(field_index)
puts "Value = #{field_value} for field named #{field_name}"
end
...
ds = ogr.Open(filename, 1)
layer = ds.GetLayer()
for i in range(len(layer.schema)):
print(layer.schema[i].name)
Related
For table cmdb_rel_ci, I want to retrieve unique parent.sys_class_name with count for "type=In Rack::Rack contains". I am doing practice in out of the box instance.
At table level URL is as below:
URL
I want to retrieve result from above URL with my below script.
var count = new GlideAggregate('cmdb_rel_ci');
count.addQuery('type','e76b8c7b0a0a0aa70082c9f7c2f9dc64');// sys_id of type In Rack::Rack contains e76b8c7b0a0a0aa70082c9f7c2f9dc64
count.addAggregate('COUNT', 'parent.sys_class_name');
count.query();
while(count.next()){
var parentClassName = count.parent.sys_class_name.toString();
var parentClassNameCount = count.getAggregate('COUNT','parent.sys_class_name');
gs.log(parentClassName + " : " + parentClassNameCount );
}
The issue is I am getting parentClassName empty.
Try this instead:
var parentClassName = count.getValue("parent.sys_class_name")
Since it's a GlideAggregate query (instead of GlideRecord), the query being issued isn't returning all of the fields on the target table. With GlideRecord, dot-walking through a reference field (e.g. parent.sys_class_name) automatically resolves that referenced record to provide access to its field values. This is made possible by the fact that the driving/original query brought back the value of the parent field. This is not happening with GlideAggregate. The query in this case basically looks like:
SELECT cmdb1.`sys_class_name` AS `parent_sys_class_name`, count(*)
FROM (cmdb_rel_ci cmdb_rel_ci0 LEFT JOIN cmdb cmdb1 ON cmdb_rel_ci0.`parent` = cmdb1.`sys_id` )
WHERE cmdb_rel_ci0.`type` = 'e76b8c7b0a0a0aa70082c9f7c2f9dc64'
GROUP BY cmdb1.`sys_class_name`
ORDER BY cmdb1.`sys_class_name`
So, you actually have access specifically to that dot-walked sys_class_name that's being grouped, but not through the dot-walk. The call to getValue("parent.sys_class_name") is expectedly resolved to the returned column aliased as parent_sys_class_name.
That being said, what you're doing probably should also work, based on user expectations, so you've not done anything incorrect here.
I am using Odoo v10. While scanning a barcode, a string contains some characters of a char field value. For example,
A field value ('tracknum') = "20171103"
Search the field by entering a string "xxxxxx20171103" or "xxxx20171103yyy"
is there any way to do it?
I have modified the search view :
<field name="tracknum" string="Tracknum" filter_domain="..."/>
How to dig out related records?
You can create an auxiliar computed field like this
custom_name = fields.Char(
string='Custom',
compute='_compute_custom_name',
search='_search_custom_name'
)
#api.multi
#api.depends()
def _compute_custom_name(self):
''' The field has to be a computed field
You do not need to do anything here
'''
pass
def _search_custom_name(self, operator, value):
''' Actually this converts a domain into another one.
With this new domain Odoo can search well
Arguments:
* operator: if you are searchig words it is going to be ilike
* value: the string ro search
The method could return something like this
* [('id', 'in', id_list)]
'''
all_records = self.search([]) # recordset with all the values of the current model
ids = []
if operator == 'ilike':
ids = all_records.filtered(lambda r: r.tracknum in value).mapped('id')
return [('id', 'in', ids)]
Then you can add this field to the search view like this:
<field name="custom_name" string="Tracking Number" />
Keep in mind that it is not a stored field, so it is going to be very inefficient. And you should iterate over all the values each time you want to make a search.
Once you have added the field to the search view it shoul look like this, Tracking Number should appear in the field name
Currently I'm working on legacy application, that uses crystal report engine. I have to get value of database fields programmatically. As I've assumed, I need proper event for getting next code to work:
Report.Database.Tables(1).Fields(1).Value
But the value is always empty in DownloadStarted/Finished event handlers. What I'm doing wrong and is it at least possible?
I think that if you want to get value of your table fields in program the best way is that you get the field name from report and then connect to your table directly and use report field names as the table columns name
i do it in c# i hope it can help you in vb6 too:
string name = report2.Database.Tables[1].Fields[1].Name;
string[] names = name.Split('.');
and then add your database to your program and use names like this:
DataTable dt = new DataTable();
string[] value = dt.Columns[names[1]];
if you just need your tables values, you can use my last answer, but if you need value of database fields in crystal report, i mean something like formula field ,this code can help you:
CRAXDRT.FormulaFieldDefinitions definitions = report2.FormulaFields;
string formulaText = "IF " + report2.Database.Tables[1].Fields[3].Name
+ " > 10 THEN" + report2.Database.Tables[1].Fields[2].Name;
definitions.Add("Test", formulaText);
report2.Sections[1].AddFieldObject(definitions[1], 0, 0);
I have records with a 'resource' field which can contain multiple resources. When I return this data, I need to iterate over this field and return an individual record for each value in the field. I am currently using sinatra and am able to interate over the fields okay, but I am having difficulty replacing the field in the json array.
For example
event: Name
resources: resourceA, resourceB, resourceC
This record needs to be returned as 3 uniqe records/events with only one resource per record.
With the code listed below, I am getting three records, but all three records are coming back with the same resource value (resourceC)
Here is my code
docs = #db.view('lab/events', :startkey => params[:startDate], :endkey => endSearch)['rows']
rows = Array.new
docs.each do |doc|
resources = doc['value']['resources'].split(",")
resources.each do |r|
doc['value']['resources'] = r
rows.push(doc['value'])
end
end
Any help is greatly appreciated.
Thanks
Chris
if you use the ruby gem "json" you can convert the json string to a hash
require 'json'
converted_hash = JSON(json_string).to_hash
This should be much easier to manage.
You can then turn the hash to a JSON string:
new_json_string = converted_hash.to_json
Basically what is happening is ruby is seeing all three records as the same record so as the hash value is updated on one record, it impacts all other records that were created from the same doc. To get around this, I acutally needed to create a duplicate record each time through and modify it's value.
docs = #db.view('lab/events', :startkey => params[:startDate], :endkey => endSearch)['rows']
rows = Array.new
docs.each do |doc|
resources = doc['value']['resources'].split(",")
resources.each do |r|
newDoc = doc['value'].dup # <= create a duplicate record and update the value
newDoc["resources"] = r
rows.push(newDoc)
end
end
How can I interact with objects I've created based on their given attributes in Ruby?
To give some context, I'm parsing a text file that might have several hundred entries like the following:
ASIN: B00137RNIQ
-------------------------Status Info-------------------------
Upload created: 2010-04-09 09:33:45
Upload state: Imported
Upload state id: 3
I can parse the above with regular expressions and use the data to create new objects in a "Product" class:
class Product
attr_reader :asin, :creation_date, :upload_state, :upload_state_id
def initialize(asin, creation_date, upload_state, upload_state_id)
#asin = asin
#creation_date = creation_date
#upload_state = upload_state
#upload_state_id = upload_state_id
end
end
After parsing, the raw text from above will be stored in an object that look like this:
[#<Product:0x00000101006ef8 #asin="B00137RNIQ", #creation_date="2010-04-09 09:33:45 ", #upload_state="Imported ", #upload_state_id="3">]
How can I then interact with the newly created class objects? For example, how might I pull all the creation dates for objects with an upload_state_id of 3? I get the feeling I'm going to have to write class methods, but I'm a bit stuck on where to start.
You would need to store the Product objects in a collection. I'll use an array
product_collection = []
# keep adding parse products into the collection as many as they are
product_collection << parsed_product_obj
#next select the subset where upload_state_ud = 3
state_3_products = product_collection.select{|product| product.upload_state_id == 3}
attr reader is a declarative way of defining properties/attributes on your product class. So you can access each value as obj.attribute like I have done for upload_state_id above.
select selects the elements in the target collection, which meet a specific criteria. Each element is assigned to product, and if the criteria evaluates to true is placed in the output collection.