Here's the structure part of my collection :
{
...
likes: ['6a6ca923517f304900badd98','6a6ca923517f304900badd99','...'],
...
}
Which method could you advise me to retrieve the list of values in the "likes" field with C lib please ?
I don't have a working MongoDB C driver, but this should help get you started. Also, the docs should help you (here).
bson_iterator i[1], sub[i];
bson_type type;
const char * key;
const char * value;
// do query, get cursor
while(mongo_cursor_next(cursor) == MONGO_OK) {
// look for the "likes" field
if( bson_find( iterator, bson, "likes" )) {
// need to iterate through the elements of the array
bson_iterator_subiterator( iterator, sub );
// then iterate using "sub", until returns a BSON_EOO
while (BSON_EOO != bson_iterator_next( sub )) {
key = bson_iterator_key( sub );
// if it's a string...
value = bson_iterator_string( sub );
}
}
}
Related
I have a collection with a key called fields, which is an array of JSON objects. Those objects can have options which is another array of JSON objects. I’m trying to update one of the options by optionId. I tried this but it doesn't work.
Projects.update({
'fields.options._id': optionId
}, {
$set: {
`fields.$.options.$.title`: title
}
}
This does find the correct Project document, but doesn't update it.
You can use the $ operator for single level arrays only. Use of array1.$.array2.$.key is not supported.
However, if you are aware of the exact index of the element to be updated within the array, you can update like so:
Projects.update({
'fields.options._id': optionId
}, {
$set: {
`fields.0.options.1.title`: title
}
}
This is one way to update:
Projects.find({"fields.options._id":optionId}).forEach(function(record) {
var match = false;
// iterate fields array
for(var i=0; i< record.fields.length; i++){
// iterate options array
for(var j=0; j<record.fields[i].options.length; j++){
if(record.fields[i].options[j]._id == optionsID){
record.fields[i].options[j].title = title;
match = true;
// break;
}
}
}
if (match === true) Projects.update( { 'fields.options._id': optionId }, record );
});
Source
Here's the structure part of my collection :
{
...
list: [
{ id:'00A', name:'None 1' },
{ id:'00B', name:'None 2' },
],
...
}
Which method could you advise me to retrieve the list of values in the "id" and/or "name" field with C lib please ?
It seems you are asking for the equivalent of "db.collection.distinct" with the C driver. Is that correct? If so, you can issue distinct as a db command using the mongo_run_command function:
http://api.mongodb.org/c/current/api/mongo_8h.html#a155e3de9c71f02600482f10a5805d70d
Here is a piece of code you may find useful demonstrating the implementation:
mongo conn[1];
int status = mongo_client(conn, "127.0.0.1", 27017);
if (status != MONGO_OK)
return 1;
bson b[1]; // query bson
bson_init(b);
bson_append_string(b, "distinct", "foo");
bson_append_string(b, "key", "list.id"); // or list.name
bson_finish(b);
bson bres[1]; // result bson
status = mongo_run_command(conn, "test", b, bres);
if (status == MONGO_OK){
bson_iterator i[1], sub[1];
bson_type type;
const char* val;
bson_find(i, bres, "values");
bson_iterator_subiterator(i, sub);
while ((type = bson_iterator_next(sub))) {
if (type == BSON_STRING) {
val = bson_iterator_string(sub);
printf("Value: %s\n", val);
}
}
} else {
printf("error: %i\n", status);
}
The database is "foo" and the collection, containing documents similar to yours, is "test" in the above example. The query portion of the above is equivalent to:
db.runCommand({distinct:'foo', key:'list.id'})
Hope that helps.
Jake
Here's the structure part of my collection :
{
_id: {
id:"6a6ca923517f304900badd98",
target:"00badd6a6ca923517f304998e4df"
},
...
}
The use of :
if(bson_find(iterator, mongo_cursor_bson(cursor), "_id")){
bson_iterator_subiterator(iterator, sub);
id = (char*)bson_iterator_string(sub);
}
is "working" but in reality simply returns me the result of the first field of the array found...
How to recover precisely the value of the "id" or "target" field please ?
You can also use bson_iterator_more and bson_iterator_next upon the sub-iterator(It was still an iterator).
try this:
if(bson_find(iterator, mongo_cursor_bson(cursor), "_id"))
{
bson_iterator_subiterator(iterator, sub);
while(bson_iterator_more(sub))
{
if (bson_iterator_next(sub) != BSON_EOO)
{
printf("%s: %s\n", bson_iterator_key(sub), bson_iterator_string(sub));
}
}
}
I'm doing a MapReduce in Mongo to generate a reverse index of tokens for some documents. I am having trouble accessing document's _id in the map function.
Example document:
{
"_id" : ObjectId("4ea42a2c6fe22bf01f000d2d"),
"attributes" : {
"name" : "JCDR 50W38C",
"upi-tokens" : [
"50w38c",
"jcdr"
]
},
"sku" : "143669259486830515"
}
(The field ttributes['upi-tokens'] is a list of text tokens I want to create reverse index for.)
Map function (source of the problem):
m = function () {
this.attributes['upi-tokens'].forEach(
function (token) { emit(token, {ids: [ this._id ]} ); }
); }
Reduce function:
r = function (key, values) {
var results = new Array;
for (v in values) {
results = results.concat(v.ids);
}
return {ids:results};
}
MapReduce call:
db.offers.mapReduce(m, r, { out: "outcollection" } )
PROBLEM Resulting collection has null values everywhere where I'd expect an id instead of actual ObjectID strings.
Possible reason:
I was expecting the following 2 functions to be equivalent, but they aren't.
m1 = function (d) { print(d['_id']); }
m2 = function () { print(this['_id']); }
Now I run:
db.offers.find().forEach(m1)
db.offers.find().forEach(m2)
The difference is that m2 prints undefined for each document while m1 prints the ids as desired. I have no clue why.
Questions:
How do I get the _id of the current object in the map function for use in MapReduce? this._id or this['_id'] doesn't work.
Why exactly aren't m1 and m2 equivalent?
Got it to work... I made quite simple JS mistakes:
inner forEach() in the map function seems to overwrite 'this' object; this is no longer the main document (which has an _id) but the iterated object inside the loop)...
...or it was simply because in JS the for..in loop only returns the keys, not values, i.e.
for (v in values) {
now requires
values[v]
to access the actual array value. Duh...
The way I circumvented mistake #1 is by using for..in loop instead of ...forEach() loop in the map function:
m = function () {
for (t in this.attributes['upi-tokens']) {
var token = this.attributes['upi-tokens'][t];
emit (token, { ids: [ this._id ] });
}
}
That way "this" refers to what it needs to.
Could also do:
that = this;
this.attributes['upi-tokens'].forEach( function (d) {
...
that._id...
...
}
probably would work just fine.
Hope this helps someone.
I run an IRC bot and I have a function which returns 1 random url using Math.random at the moment, from my Mongodb collection.
I would like to refactor it to return x number of unique items, and for each subsequent invocation of the url fetching command .getlinks I would like that it keeps everything unique, so that a user doesn't see the same link unless all the possible links have been already returned.
Is there some algorithm or native mongodb function I could use for this?
Here's a sample scenario:
I have a total of 9 records in the collection. They have a _id and url field.
user a: .getlinks()
bot returns: http://unique-link-1, http://unique-link-2, http://unique-link-3, http://unique-link-4
user a: .getlinks()
bot returns: http://unique-link-5, http://unique-link-6, http://unique-link-7, http://unique-link-8
user a: .getlinks()
bot returns: http://unique-link-9, http://unique-link-6, http://unique-link-1, http://unique-link-3
Background information:
There's a total of about 200 links. I estimate that will grow to around 5000 links by the end of next year.
Currently the only thing I can think of is keeping an array of all returned items, and grabbing all items from the collection at once and getting a random one 4 times and making sure it's unique and hasn't been shown already.
var shown = [], amountToReturn = 4;
function getLinks() {
var items = links.find(), returned = [];
for ( var i = 0; i<amountToReturn; i++ ) {
var rand = randItem( items );
if ( shown.indexOf( rand.url ) == -1 && shown.length < items.length ) ) {
returned.push( rand.url );
}
}
message.say( returned.join(',') );
}
You should find a number of possible options to get random item(s) from Collection here ...
http://jira.mongodb.org/browse/SERVER-533
Another intersting method is documented here ...
http://cookbook.mongodb.org/patterns/random-attribute/
The method mentioned above basically creates a new key/value on the document using Math.random()
> db.docs.drop()
> db.docs.save( { key : 1, ..., random : Math.random() } )
> db.docs.save( { key : 1, ..., random : Math.random() } )
> db.docs.save( { key : 2, ..., random : Math.random() } )
... many more insertions with 'key : 2' ...
> db.docs.save( { key : 2, ..., random : Math.random() } )
...
Get random records form mongodb via map/reduce
// map
function() {
emit(0, {k: this, v: Math.random()})
}
// reduce
function(k, v) {
var a = []
v.forEach(function(x) {
a = a.concat(x.a ? x.a : x)
})
return {a:a.sort(function(a, b) {
return a.v - b.v;
}).slice(0, 3 /*how many records you want*/)};
}
// finalize
function(k, v) {
return v.a.map(function(x) {
return x.k
})
}