I Want to query CouchDB and I have a specific need : my query should return the name field of documents corresponding to this condition : the id is equal or contained in a document filed (a list).
For example, the field output is the following :
"output": [
"doc_s100",
"doc_s101",
"doc_s102",
"doc_s103",
],
I want to get all the documents having in their output field "doc_s102" for example.
I wrote a view in a design document :
"backward_by_docid": {
"map": "function(doc) {if(doc.output) emit(doc.output, doc.name)}"
}
but this view works only when I have a unique value in the output field.
How can I resolve this query ?
Thanks !
you have to iterate over the array:
if(doc.output) {
for (var curOutput in doc.output) {
emit (doc.output[curOutput],doc.name);
}
}
make sure that output always is an array (at least [])
.. and, of course use key="xx" instead key=["xxx"]
Related
I have a field in my application like below.
{
"Ct": "HH",
Val:{
"Count":"A",
"Branch":"A"
}
}
When I'm trying to retrieve this using below command in CouchDB, I'm unable to retrieve records.
{
"selector" : {
"Val":{
"$elemMatch":{
"Count":"A"
}
}
}
From the CouchDB documentation,$elemMatch[1]
Matches and returns all documents that contain an array field with at
least one element that matches all the specified query criteria.
Val.Count is not an array field so $elemMatch is not appropriate.
Consider the CouchDB documentation regarding subfield queries[2]:
1.3.6.1.3. Subfields
A more complex selector enables you to specify the values for field of
nested objects, or subfields. For example, you might use a standard
JSON structure for specifying a field and subfield.
Example of a field and subfield selector, using a standard JSON
structure:
{
"imdb": {
"rating": 8
}
}
An abbreviated equivalent uses a dot notation to combine the field and
subfield names into a single name.
{
"imdb.rating": 8
}
Specifically,
selector: {
"Val.Count": "A"
}
1 CouchDB: 1.3.6.1.7. Combination Operators
2 CouchDB: 1.3.6.1.3. Subfields
I have a database collection where each row has a unique ID associated with it. I want to be able to query my database and match data from it with the IDs in each of the objects from an array. The _ids are a string.
Collection Example:
"_id" : "453241",
"name" : "Item1",
"_id" : "621984",
"title" : "Item2",
"_id" : "832127",
"title" : "Item3",
The object would look something like this:
query = [{"_id":"621984","quantity":"3"},{"_id":"832127","quantity":"2"}]
The desired output would be something like this (I do not want to write to the database the quantity):
output = [{"_id":"621984","Item2", "quantity":"3"},{"_id":"832127", "Item3" ,"quantity":"2"}]
From the other threads, I read from what I understand we have to use the $is to match the data. Like the one in this example MongoDB select where in array of _id? However, the issue with this is that they are using an array of IDs. And I'm not sure how we would append the quantity to this value.
I also considered iterating through a loop of all of the objects inside of the array and then searching the database. And appending the output to an array. This would be most beneficial as I would want the overall output to include the quantity as well.
console.logging result in this case works and outputs the designated ID table however when attempting to append the values to output and then returning this does not work and returns an empty array.
output = []
for (item in query) {
collection.find({"id": item._id}).then((result) => { output.push(result + item.quantity) })
}
return output
Any ideas or help would be greatly appreciated thanks.
I've run into very similar situations with my own implementations as far as efficiency is concerned. The approach that I ended up taking (granted in a one-to-many relationship) is the following.
Isolate the Ids into an array prior to the Mongoose Query
let ids = []
for (object in query) {
ids.push(query[object]._id)
}
collection.find({ id : $in : ids }).then((result) => {
for (let i in result) {
for (let j in query) {
if (result[i]._id === query[j]._id) {
query[j].name = result[i].name
}
}
}
}).catch((error) => {
console.log("Query Error")
})
Also, in the above example, taking the array of Ids is going to require the Mongo $in operator to search through the array and return the appropriate collection items.
I hope this helps!
I am trying to set up a search index using Cloudant, but I find the documentation pretty confusing. It states:
FACETING
In order to use facets, all the documents in the index must include all the fields that have faceting enabled. If your documents do not include all the fields, you will receive a bad_request error with the following reason, “dim field_name does not exist.”
If each document does not contain all the fields for facets, it is recommended that you create separate indexes for each field. If you do not create separate indexes for each field, you must include only documents that contain all the fields. Verify that the fields exist in each document using a single if statement.
Counts
The count facet syntax takes a list of fields, and returns the number of query results for each unique value of each named field.
The count operation works only if the indexed values are strings. The indexed values cannot be mixed types. For example, if 100 strings are indexed, and one number, then the index cannot be used for count operations. You can check the type using the typeof operator, and convert using parseInt, parseFloat and .toString() functions.
Specifically, what does it means when "all the documents in the index include all the fields that have faceting enabled".
For example, if my database consists of the following doc:
{
"_id": "mydoc"
"subjects": [ "subject A", "subject B" ]
}
And I write a search index like so:
function (doc) {
for(var i=0; i < doc.subjects.length; i++)
index("hasSubject", doc.subjects[i], {facet: true});
}
Would this be illegal because mydoc doesn't have a field called hasSubject? And when we rewrite the query to look like;
{
"_id": "mydoc"
"hasSubject": true,
"subjects": [ "subject A", "subject B" ]
}
Would that suddenly make it OK...?
So the new documentation is at https://console.ng.bluemix.net/docs/services/Cloudant/api/search.html#faceting ; however, the entry on faceting is the same. So no big deal there.
To answer your question though, I think what the documentation is saying is that all the JSON docs in your database must contain the subjects field, which is what you're declaring you want to facet on in your example.
So I would also consider defining your search index like so:
function (doc) {
if (doc.subjects) {
for(var i=0; i < doc.subjects.length; i++) {
if (typeof doc.subjects[i] == "string") {
index("hasSubject", doc.subjects[i], {facet: true});
}
}
}
}
And if you had a doc like this in your database:
{
"_id": "mydoc"
"hasSubject": true,
}
I think that would suddenly make your facets NOT ok.
I have one collection, called "games" whose documents store the ids of the owners of games.
{
"owner" : "88878b6c25c167d"
}
{
"owner" : "88878b6c25c167d"
}
{
"owner" : "af565f77f73469b"
}
Then I have another collection called "users".
{
"id" : "af565f77f73469b"
}
{
"id" : "a881335e1d4cf17"
}
{
"id" : "aa3ce3f7767c46b"
}
{
"id" : "d19e52c0bd78bcb"
}
{
"id" : "88878b6c25c167d"
}
So the first query I do retrieves the owners of all the games and stores those values in an array.['88878b6c25c167d', '88878b6c25c167d', 'af565f77f73469b']
The second query I want to perform should retrieve the documents of the users with the corresponding IDs. Previously I had used this query:
db.users.find({'id':
{'$in': [
'88878b6c25c167d',
'88878b6c25c167d',
'af565f77f73469b'
]}})
Here's the problem with this: It does not return duplicate documents if a user is listed twice, as above. Instead I just get one. This breaks my application. How can I make sure that each owner returns a document?
MongoDB works perfectly fine --- it finds all user, whose id-s are contained in the array.
Do not know the broader context of your needs (maybe tell us what you want to achieve -- not what is wrong?), but if you want to have an association between games and users something like that may be suitable:
after retrieving collection of games; just create an auxiliary hash map (normal JS object) that for given owner id will return the array of its games.
retrieve info about users who are owners.
if you want to know, which games belong to particular user just pass her id to data structure from 1. and get the arrays with games.
Is it what you were looking for? Do you need help with 1.?
Is it possible to use similiar query in CouchDB? Like use two keys?
SELECT field FROM table WHERE value1="key1" OR value2="key2"
I was always using only one key.
function(doc) {
emit(doc.title, doc);
}
Thank you.
In CouchDB 0.9 and above you can POST to a view (or _all_docs) with a body like:
{"keys": ["key1", "key2", ...]}
In order to retrieve the set of rows with the matching keys.
Yes. Something like this should do the trick if I understand your question:
function(doc) {
a = (doc.value1 && doc.value1 == "key1");
b = (doc.value2 && doc.value2 == "key2");
if (a || b) {
emit(doc._id,doc.title);
}
}
Only emit the documents or values you need.
I'd add this to duluthian's reply:
emit(doc.title, null)
You can always pull out the "_id" and doc values using the view api.
You could create a view like this:
function(doc){
if(doc.value1) emit(doc.value1, doc.field);
if(doc.value2) emit(doc.value2, doc.field);
}
Then query it using llasram's suggestion to POST to the view with:
{"keys": ["key1", "key2", ...]}
Your client will have to be wary of dups though. A document where doc.value1 == "key1" && doc.value2 == "key2" will show up twice. Just use _id to filter the results.
One needs to expand a little bit on llasram's answer; the index must contain the values for both fields:
function(doc) {
emit("value1:"+doc.value1); // add check for undefined, null, etc.
emit("value2:"+doc.value2);
}
then query with
keys=["value1:key1","value2:key2"]
EDIT: This will however report the same document multiple times if it contains the matching value+key pairs.
You could do this ( assuming you want "dynamic parameters" ) by using 2 separate views, and a little client-side processing:
You would have one view on "field1", which you would query with "value1".
( getting a list of document IDs )
Then you query a second view on "field2", passing "value2", and getting another list of Doc IDs.
Now, you simply have to find the "intersection" of the 2 lists of ID numbers
( left as an exercise for the reader )