Hi I have some trouble with arrays in mongodb. To read a document with java is no problem but to read an array what is in a document is a problem. Lets say I have a collection myCol:
{"name": "lenny linux", "gender": "m", "computers": [{"name": "computer"}, {"name": "computer2"} {"name"...}]}
So there is an array with computers. I could read the whole document with
DBCollection myCol = getCollection(...);
BasicDBObject query = new BasicDBObject();
query.put(name, "lenny linux");
DBCursor cursor = myCol.find(query);
while (cursor.hasNext()) {
System.out.print(cursor.next());
}
But I just need the names of the computers, so I have to read somehow the array. Dont get this array stuff in mongodb. And also what if I would like to delete something from a mongodb array? Its not the same as to delete a normal document... thank you for any help!
Edit: If im reading the mongodb page: http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-ValueinanArray I really dont get it. They have there an array of colors and then they are reading red like this:
db.things.find({ colors :"red" });
Why would I do this? If I want to read an array to know whats inside the array. The user dont know that there is a "red" or blue or whatever. Maybe the array colors is empty? Then I get back a null, 0 or whatever and if there are 4 colors then give me these colors, print it out. I dont have any other examples...im sorry for my bad english.
Edit2:
Ok so the new solution for me is to get the whole document where name == lenny linux (like at the first time in my code) and then to parse this document with an extern JSON parser like json-simple. Well maybe thats not the best solution, because the best solution would be to get the stuff in the array without other libs just using the mongolib... but ok its working :) If somebody knows an easier way just post it here. Thank you.
And also what if I would like to delete something from a mongodb
array? Its not the same as to delete a normal document.
http://www.mongodb.org/display/DOCS/Updating explains 2 ways:
$set: to replace the current array with a new one (fetch the previous array, remove an element or two, and update with $set)
db.users.update({name : "lenny linux"}, {$pull : { computers : { name : "computer2" } }}, false, false) to remove all elements from the array computers that have name 'computer2'.
When reaching into an array with objects (named elements), you want to use the dot notation to reach into the array.
db.myColl.find({'computers.name':'computer'});
http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-ValueinanArray
as for removing items from an array, you want to look at the $pop and $pull update functions
http://www.mongodb.org/display/DOCS/Updating
Since I was dealing with this problem in Java, and your code is in Java, here is the solution ... in java.
Basically when you get(key) a MongoDB array, it returns a com.mongodb.BasicDBList object that you can get an iterator for.
In my code, I query documents that look like this:
{
"_id": ObjectID("52d60db91f3aa664410bcde5"),
"owner": "Amy",
"trusted": [
"amy",
"paul",
"randy"
]
}
And when I ever need to find the trusted people of this document, I use ((BasicDBList) doc.get("trusted")).listIterator();
DBObject doc = collection.findOne(new BasicDBObject("owner", "Amy"))
ListIterator<Object> trustedList = ((BasicDBList) doc.get("trusted")).listIterator();
while(trustedList.hasNext()){
Object nextItem = trustedList.next();
System.out.println(nextItem.getClass()); // String
// Here I handle what to do to each name.
// I could add them to an ArrayList<String> if I needed
updateTrustee((String)nextItem);
}
I came to this solution using a few System.out.println(Object.getClass())s to know what classes I needed to cast.
The question he is asking is how does one return ALL the elements found in an array stored in a Mongo collection without knowing precisely how many or what these elements might be. You are not performing a query against a known value, rather you are simply asking for a dump of what is in the Mongo array. For example, if your Mongo array name is "colors", simply do the following:
#colors = #{$record->{colors}};
Now you have all the colors in a Perl array for you to play with.
Enjoy!
Related
I have a MongoDB database and the program I'm writing is meant to change the values of a single field for all documents in a collection. Now if I want them all to change to a single value, like the string value "mask", then I know that updateMany does the trick and it's quite efficient.
However, what I want is an efficient solution for updating to different new values, in fact I want to pick the new value for the field in question for each document from a list, e.g. an ArrayList. But then something like this
collection.updateMany(new BasicDBObject(),
new BasicDBObject("$set",new BasicDBObject(fieldName,
listOfMasks.get(random.nextInt(size)))));
wouldn't work since updateMany doesn't recompute the value that the field should be set to, it just computes what the argument
listOfMasks.get(random.nextInt(size))
would be once and then it uses that for all the documents. So I don't think there's a solution to this problem that can actually employ updateMany since it's simply not versatile enough.
But I was wondering if anyone has any ideas for at least making it faster than simply iterating through all the documents and each time do updateOne where it updates to a new value from the ArrayList (in a random order but that's just a detail), like below?
// Loop until the MongoCursor is empty (until the search is complete)
try {
while (cursor.hasNext()) {
// Pick a random mask
String mask = listOfMasks.get(random.nextInt(size));
// Update this document
collection.updateOne(cursor.next(), Updates.set("test_field", mask));
}
} finally {
cursor.close();
}```
MongoDB provides the bulk write API to batch updates. This would be appropriate for your example of setting the value of a field to a random value (determined on the client) for each document.
Alternatively if there is a pattern to the changes needed you could potentially use find and modify operation with the available update operators.
I am using Json Patch library to perfrom a Patch operation using REST. Now I have the follwoing json document:
{
"id":1,
"ref":{"r1":1,"r2":2}, // header level
"child":[
{
"childId":1,
"ref":{"cc1":1,"cc2":2} // line level
},
{
"childId":2,
"ref":{"cc3":2} // line level
}
]
}
Now As per Json Patch doc we at the header level we can update the ref r1 using the following path /ref/r1 .
Now I am trying to perform operation on the line level child ref. Since child is an array I can use the path /child/0/ref/cc1. But as can be seen from the path I have to specify the index also which is 0 in the previous case.
Now for API consumers asking them to give the index of the array become difficult. So is there any way to customize json patch so that we can bypass the index requirement or what are the other ways to handle this scenario?
I'm not an expert in JSON-Patch, i've just read about it.
from what i understood, is the most important part is to let the API consumers access to your JSON without giving them index,
I think hashmap would help in this case, by getting the index of each element and generate a specific ID for it, then you can save them in the hashmap list, each index has its own ID.
a sample:
HashMap<String, String> elementIndex = new HashMap<[UUID], [elementIndex]>();
you can choose whatever DataType you want, not necessary String
In this case it doesn't matter which index number, it is all about the fixed UUID.
So the path will be in this case /child/{UUID}/ref/cc1 also when you receive the path you can access the UUID and replace it with its elementIndex, now you have the correct path which is /child/0/ref/cc1
and if you want to know how to pass a dynamic value to a JSON Object, there are multiple ways to do it,
this question will help:
How to pass dynamic value to a JSON String, -Convert the JSONObject to String before-
NOTE: It is not necessary to replace it with index, you can do it the way you like could be.
And i believe there are better answers if someone knows more about JSON-patch.
i hope that was helpful, or at least gives you an idea about how to solve it.
This is one of the sample document which I saved in my bucket,
{
"id": "639882607203778560",
"text": "How does Andy Reid describe the no WR touchdown stat?",
"name": "chiefs",
"createdAt": 1441394876000,
}
I need to fetch the documents for given name and the date range. So this is the view I created for it,
function (doc, meta) {
if (doc._class == "com.link.data" && doc.createdAt && doc.name) {
emit([doc.createdAt,doc.name], null);
}
}
This will give me the all documents for given date range but it doesn't filter based on name. I have all the documents with other names also. How can I achieve this? Also what is the correct implementation for java?
This is the my current impl and I want to do this without using N1ql.
query.setRange(ComplexKey.of(1441376400000L, name), ComplexKey.of(1441396800000L,name));
I tried to add range as a startKey and endKey.Then put the name as a key in couchbase UI and it doesn't work.
Disclaimer: I dont have a lot of experience with compound/complex keys in CB.
I believe what you're asking for cannot be done with a single view: Sorting on date and then filtering on a specific name. You can sort on range and then group-by name, but you'd still get all the various names in the bucket (as you've already noticed).
What you can do is use two separate views and then intersect the results: get the doc-ids with the name you want, get the docs in the range you want and find intersections in your java code. Since views are only 'eventually consistent', your results are just as good as with a single view request, so the only thing you're wasting here is bandwidth and a little time, but not result-precision.
"given" means exact match?
If you want to get result with exact matched name with date range, try emit() with:
emit([doc.name, doc.createdAt], null);
the key array itself, 1st arg in emit() function, is the sort order.
I've got a view that contains documents with various questions I want answered about Purchase Orders.
Using a repeat, I list all the questions. There are a few different kinds of questions, so I only render the answer field that I need based on the FieldType column value. I want to pull the choices for a combobox from the DialogChoices field on the question document.
I'm currently getting the choices showing as plain text on the next line after the empty combobox instead of as the selectItems. Where is my code going wrong?
<xp:comboBox id="comboBox1">
<xp:this.rendered><![CDATA[#{javascript:rowData.getColumnValue("FieldType") == "Dialog Box"; }]]></xp:this.rendered>
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript:var doc:NotesDocument = rowData.getDocument();
var choicesVector:java.util.Vector= doc.getItemValue("DialogChoices");
var choices = [];
// loop through the vector, doing push into the array
for (i=0; i<choicesVector.size(); i++) {
choices.push (choicesVector.elementAt(i))
};
return choices;}]]>
</xp:this.value>
</xp:selectItems>
</xp:comboBox>
Strange, but a test database with the code above does not seem to give me strange results. Maybe it is because the data is in fact not an Vector but just a string?
Here are some tips :
The first thing you could change in your code is the loop to get all the data out of your field. Since the value property of a combobox already expects an array or vector you can change the code to something like:
<xp:this.value><![CDATA[#{javascript:var doc:NotesDocument = rowData.getDocument();
return doc.getItemValue("DialogChoices");
}]]>
</xp:this.value>
But it would be even better to remove the getDocument call at all. If possible you can add a column to the view are you are using for the repeat's datasource. In this column you get the data from the field directory. This way you can use the viewentry's getColumnValue() which is a performance optimization. Something like:
<xp:selectItems>
<xp:this.value><![CDATA[#{try{
return rowData.getColumnValue("DialogChoices");
}catch(e){// do something }]]>
</xp:this.value>
</xp:selectItems>
I have a very simple question...
In my Android app i'm forming a JSON string to send to my server... there are no error in my code, but Java (or Android) puts the values in a different order of mine and I don't know why...
I want to solve this issue, because I need to process that JSON string in the server to update some tables of my database... my PHP code in the server uses the same order I used in my app to decode the JSON string, but because of Android (or Java) that changes the order, I'm having troubles to update the tables...
Any ideas? Thanks in advance!
I'm talking about this:
In my app:
json_data.put("id_visit", visits.getString(visits.getColumnIndexOrThrow("id_visit")));
json_data.put("id_form", visits.getString(visits.getColumnIndexOrThrow("id_form")));
json_data.put("id_establishment", visits.getString(visits.getColumnIndexOrThrow("id_establishment")));
json_data.put("id_promoter", visits.getString(visits.getColumnIndexOrThrow("id_promoter")));
json_data.put("actual_date", visits.getString(visits.getColumnIndexOrThrow("actual_date")));
json_data.put("receiver", visits.getString(visits.getColumnIndexOrThrow("receiver")));
json_data.put("observations", visits.getString(visits.getColumnIndexOrThrow("observations")));
json_data.put("gps_coordinates", visits.getString(visits.getColumnIndexOrThrow("gps_coordinates")));
In the LogCat:
{
"id_promoter":"1",
"id_establishment":"5",
"id_visit":"1",
"receiver":"brenda lopez",
"gps_coordinates":"10.4905567 -66.8710966",
"actual_date":"2012-11-27",
"id_form":"1",
"observations":"observaciones"
}
As you can see, its not te same order! Why is this?
I apologize for not taking the time of checking if someone else already asked this, but I'm in a little hurry, so... Sorry!! xD
Object keys are not ordered in JSON. If you need a specific order, I suggest you use an array:
[
{"id_promoter":"1"},
{"id_establishment":"5"},
{"id_visit":"1"},
{"receiver":"brenda lopez"},
{"gps_coordinates":"10.4905567 -66.8710966"},
{"actual_date":"2012-11-27"},
{"id_formu":"1"},
{"observations":"observaciones"}
]
It's gross, but order is what arrays are for.
Another approach is to define an array with the key names in the desired order. Then you can use your original object structure but access it through keys defined by the array. This takes more coding, obviously, but it can also solve your problem.