Hi so I'm new to CouchDB looks great so far, but really struggling with what must be simple to do!
I have documents structured as:
{
"_id" : "245431e914ce42e6b2fc6e09cb00184d",
"_rev": "3-2a69f0325962b93c149204aa3b1fa683",
"type": "student",
"studentID": "12345678",
"Name": "Test",
"group: "A"
}
And would like to access them them with queries such as http://couchIP/student?group=A or something like that. Are Views what I need here? I don't understand how to take the parameter from the query in the Map functions in Views. example:
function(doc,req) {
if(req.group==='A'){
emit(doc.id, doc.name);
}
}
Is my understanding of how Couch is working wrong or what's my problem here? Thanks in advance, I'm sure this is Couch 101
Already read through http://guide.couchdb.org/ but it didn't really answer the question!
You need views to achieve the desired results.
Define the following map function inside a view of a design document. ( let's name the view "byGroup" and assume this lives in a design document named "_design/students" )
function(doc) {
if(doc.group){
emit(doc.group,null);
}
}
Results can be obtained from the following url
http://couchIP:5984/dbname/_design/students/_view/byGroup?startkey="A"&endkey="A"&include_docs=true
To have friendly url couchdb also provides url rewriting options.
You need to some further reading about views and the relevance that they return key/pair values.
It's not clear what you want to return from the view so I'll guess. If you want to return the whole document you'd create a view like:
function (doc) { emit(doc.group, doc) };
This will emit the group name as a key which you can lookup against, the whole doc will be returned as the value when you look it up.
If you want to just have access to the names of those users you want to do something like:
function (doc) { emit(doc.group, doc.name) };
Your question arises from a misconception about what a view does. Views use map/reduce to generate a representation of your data. You have no control of the output of your view in your query because the view is updated according to changes in your DB documents only.
Using a list is also not a good option. It may seem that you can use knowledge of your request in your list to generate a different output depending on the query parameters but this is wrong because couchdb uses ETags for caching and this means that most times you will get the same answer regardless of your list parameters since the underlying documents won't have changed. There is a trick though to fool couchdb in this case and this implies using two different alternating users but I wouldn't even try this way because surely there are easier ways to achieve your objectives and you can probably solve your problem using group as a key in your map function.
Related
I am having difficulty accessing all the data returned by my forms in my post function. I notice a significant discrepancy between what is displayed when I print request.POST vs. when my code accesses this data. Hopefully someone can explain this to me.
Output of print(request.POST):
print(request.POST)
<QueryDict: {'csrfmiddlewaretoken': ['AXMPO...'],
'start_date': ['2019-03-01'], 'end_date': ['2019-03-26'],
'reports': ['4', '1']}>
In order to examine the data my code is dealing with I used the json module to view the data. The behavior of my code during debugging conforms to this representation:
json.dumps(request.POST)
'{"csrfmiddlewaretoken": "AXMPO...",
"start_date": "2019-03-01", "end_date": "2019-03-26",
"reports": "1"}'
It all looks pretty similar until you see the "reports" value. The user selects these reports via an MultipleSelect widget on my form and my code is iterating through the id numbers provided. However, no matter how many reports I select I only get one ID. If anyone can explain why this is happening I would sincerely appreciate it.
Turns out this is a really old school issue. I could wish this was more prominent in the documentation though. The explanation by Simon Willson is below:
"""
This is a feature, not a bug. If you want a list of values for a key, use the following:
values = request.POST.getlist('key')
The reasoning behind this is that an API method should consistently return either a string or a list, but never both. The common case in web applications is for a form key to be associated with a single value, so that's what the [] syntax does. getlist() is there for the occasions (like yours) when you intend to use a key multiple times for a single value.
""" - Simon Willson, 13 years ago.
How to properly design REST if you have a composition? I have a TestResult entity, which has TestCaseResults entities. Both support full set of REST methods. The important fact about this (which I believe differs from many examples I found on a web) is that TestResult is not consistent if it doesn't have all of TestCaseResults How do I properly design this in REST?
Let's say I create it as separate but dependent resources: api\testresults\ and api\testresults\1\testcaseresults. When the client wants to create a test result, he needs to POST to api\testresults, then retrieve URL api\testresults\1\testcaseresutls by a link from the response, and POST all of test case results to it. This means that at some point in time the test result is not consistent until the user finishes its operation. Basically, there is no concept of the transaction here.
Let's say I create only api\testresults resource, and embed an array of test case results inside, like this:
{
"Name": "Test A"
"Results": [
{
"Measured": "BB",
...
},
...
]
...
}
Then it is easier to insert, but it still hard to work with. Simple GET to api\testresults\1\ will retrieve test result with a big amount of test case results. GET to api\testresults\ will retrieve much more! The structure of this becomes complex. Furthermore, in the real word I have a few entities like TestCaseResults belong to TestResults, so there will be a few arrays, and each could have 100-200 elements.
I could try to combine the approaches. Embed the array, but also provide links to api\testresults\1\testcaseresults and support operations there as well. Maybe on GET api\testresults\1\ I could provide TestResult without it's TestCaseResults but only with a link pointing to a resource, but on POST I could accept an array of TestCaseResults embedded (not sure though it is allowed to have different return types for POST and GET in REST) But now there are two approaches for inserting information, it is confusing and I'm still not sure it solves anything.
your approach with api\testresults\1 and api\testresults\1\testcaseresults seems promising.
As JSON does not have a fixed structure, you can add query parameters to your URL to control if results are inserted or not.
api\testresults\1?with_results=true would mean that your caller want to see the test cases in addition to the test results.
api\testresults\1\testcaseresults would still return the test case results for your test 1.
If you fear that the number of test case results is too large, you can add pagination parameters, that would be reuse in the testcaseresults call.
api\testresults\1?with_results=true&per_page=10 would include the only the 10 first results. To get more, use api\testresults\1\testcaseresults?per_page=10&page=2 and so on, as it is the dedicated endpoint.
Cheers
Note: if you want a flexible API still returning JSON data, you can give a look to GraphQL, the trendy approach.
I've a function which is called from different components, .cfms or remotely. It returns the results of a query.
Sometimes the response from this function is manually inspected - a person may want to see the ID of a specific record so they can use it elsewhere.
The provided return formats, being wddx, json, plain all aren't very easily readable for a layman.
I'd love to be able to create a new return format: dump, where the result first writeDumped and then returned to the caller.
I know there'd be more complicated ways of solving this, like writing a function dump, and calling that like a proxy by providing the component, function and parameters so it can call that function and return the results.
However I don't think it's worth going that far. I figured it'd be great if I could just write a new return format, because that's just... intuitive and nice, and I may also be able to use that technique to solve different problems or improve various workflows.
Is there a way to create custom function returnFormats in ColdFusion 10 or 11?
(From comments)
AFAIK, you cannot add a custom returntype to a cffunction, but take a look at OnCFCRequest. Might be able to use it to build something more generic that responds differently whenever a custom URL parameter is passed, ie url.returnformat=yourType. Same net effect as dumping and/or manipulating the result manually, just a little more automated.
From the comments, the return type of the function is query. That being the case, there is simply no need for a custom return format. If you want to dump the query results, do so.
queryVar = objectName.nameOfFunction(arguments);
writeDump (queryVar);
How to simply duplicate documents from collectionABC and copy them into collectionB if a condition like {conditionB:1} and add a timestamp like ts_imported - without knowing the details contained within the original documents?
I could not find a simple equivalent for mongodb which is similar to mysql's INSERT ... SELECT ...
You can use javascript from mongoshell to achieve a similar result:
db.collectionABC.find({ conditionB: 1 }).
forEach( function(i) {
i.ts_imported = new Date();
db.collectionB.insert(i);
});
I realise that this is an old question but...there is a better way of doing it now. MongoDB has now something called aggregation pipeline (v 3.6 and above, maybe some older ones too - I haven't checked). The aggregation pipeline allows you to do more complex things like perform joins, add fields and save documents into a different collection. For the OP's case, the pipeline would look like this:
var pipeline = [
{$match: {conditionB: 1}},
{$addFields: {ts_imported: ISODate()}},
{$out: 'collectionB'}
]
// now run the pipeline
db.collectionABC.aggregate(pipeline)
Relevant docs:
Aggregation pipeline
$out stage
some important limits
Mongodb does not have that kind of querying ability whereby you can (inside the query) insert to another collection based upon variables from the first collection.
You will need to pull that document out first and then operate on it.
You could technically use an MR for this but I have a feeling it will not work for your scenario.
It seems that this works in the context of sequence generation
http://docs.mongodb.org/manual/tutorial/create-an-auto-incrementing-field/
Im using Vaadin as the framework to represent a presentation layer for my application.
I have a trouble with the Vaadin Table listing. I load 1000 rows with 5 columms (yes I need to load all 1000, there is also an option to load less. =)) but this is not very fast when using Vaadin. When I look at the Json sent I realize that there are lots of variables that i dont whant to be sent for everu table row.
This is the response i have as of now:
"domaindom-000000938.co_uk",
["17",
{"id": "PID783","readonly":true,"locale": "en_EN","format": "yyyy-MM-dd","strict":true,"wn":false,"parsable":true,
"v":{"day":7,"month":2,"year":2011}}],
["17",
{"id": "PID784","readonly":true,"locale": "en_EN","format": "yyyy-MM-dd","strict":true,"wn":false,"parsable":true,
"v":{"day":7,"month":2,"year":2011}}],
["17",
{"id": "PID785","readonly":true,"locale": "en_EN","format": "yyyy-MM-dd","strict":true,"wn":false,"parsable":true,
"v":{"day":7,"month":2,"year":2012}}],
"","","ENG"],
["tr",{"key":206},"
I would like to transform this Json to be more like
"domaindom-000000938.co_uk",
["17",
{"id": "PID783","locale": "en_EN",,"strict":true,"wn":false,"v1":"2011-07-02", "v2":"2011-02-07", "v3":"2012-02-07"}],
As you can see I have removed a couple of variables and inserted the date varialble in the same clauses.
So my quiestion is this. In Vaadin, how do I modify the way Vaadin creates the Json response? I currently use the BeanItemContainer to hold my objects like this:
public BeanItemContainer getPagedDataSource(){
List<Object> mylist = DAO.getDAO().createQuery(query, index, max);
return new BeanItemContainer<Object>(type, mylist);
}
Thanks for any help or feedback!
/Marthin
First, that JSON is part of Vaadin's internal communication and you should not modify it. However, if you wish to check it out, it is the JsonPaintTarget along with the paintContent-method of the component in question (the Table) that creates the JSON.
Vaadin today operates in an unprecedented way. Everything will change in the application must be sent to the client. On the client side, each component is treated separately and therefore the response must address all components changed.
Each row in the table is a separate component because the answer is so long.
My proposed solution:
write your own implementation of the table - hard
the imposition of restrictions - easy, but it's prosthesis