I am using Mongo C APIs to implement DB Interface for a project.
MongoDB Document:
{
_id,
... // Some fields
...
Array
}
Query Used to Populate Values in the Array:
BCON_APPEND (&query, "$push", "{",
"Array", "{",
"Key", key,
"Value", (char*)value, "}",
"}");
Populated Array inside MongoDB:
"Array" : [ { "Key": "key1", "Value" : "string1" },
{ "Key": "key2", "Value" : "string2" },
{ "Key": "key3", "Value" : "string3" },
]
Query used to find the matching row in the array:
BCON_APPEND (&query, $elemMatch,
"Array", "{", "Key", key,
"}");
This query returns the complete document which contains a matching key in the array - which is fine.
Problem:
I am reading each field of the document returned by this query -- one by one.
When I encountered the Array field in the document -- my requirement is to get ONLY the matched row.
I tried to read the Array as follows:
uint32_t *document_len;
const uint8_t **document;
bson_iter_recurse (&iter, &sub_iter))
{
while (bson_iter_next (&sub_iter))
{
bson_iter_document (sub_iter,
&document_len,
document)
// Suppose my "Key" was: "key2"
// How to get the matching row: { "Key": "key2", "Value" : "string2" } as a String here ?
// Also, I want to receive ONLY matching row -- & NOT all 3 rows
}
}
I am not able to read String from this Array and also, not able to get only the matching row -- not all 3 rows.
[Note: In while() loop above, If I put this trace:
while (bson_iter_next (&sub_iter))
{
printf ("Found key \"%s\" in sub document.\n",
bson_iter_key (&sub_iter));
}
I get 3 prints:
Found key 0 in sub document
Found key 1 in sub document
Found key 2 in sub document
So, it is clear that -- I am getting all values from the array and NOT the only matching one and I cannot retrieve the actual strings from the array]
References:
Mongo C APIs https://api.mongodb.org/c/current/
libbson https://api.mongodb.org/libbson/current/bson_iter_t.html
Please help.
Related
I am looking for an array of ids, inside another array, the problem is that if it contains at least one "id" it returns the result. The validation should be that it has to have all the "ids" that I am passing.
{ subcategories: { $in: [ ObjectId('61729d550e8fe20011cc57d2', ObjectId('61693f589a34340012b1d5d8'), ObjectId('61693f2c9a34340012b1d5b7') )] } }
example:
subcategories: ["61729d550e8fe20011cc57d2", "61693f2c9a34340012b1d5b7"] -> this one should not appear, because it contains only 2 of the 3 I am looking for
I think you are looking for $all.
The docs says:
The $all operator selects the documents where the value of a field is an array that contains all the specified elements
db.collection.find({
subcategories: {
$all: [
"61729d550e8fe20011cc57d2",
"61693f589a34340012b1d5d8",
"61693f2c9a34340012b1d5b7"
]
}
})
Example here
I have this collection :
{
username : "user1",
arr : [
{
name : "test1",
times : 0
},
{
name : "test2",
times : 5
}
]
}
I have an array with some object. This objects have a name and the value times. Now I want to add new objects, if my array doesn't contain them. Example:
I have this two objects with the name "test1" and "test2" already in the collection. I want now to insert the objects "test2", "test3" and "test4". It should only add the object "test3" and "test4" to the array and not "test2" again. The value times doesn't do anything in this case, they should just have the value 0 when it gets insert.
Is there a way to do this with one query?
If you can insert test1, test2,... one by one, then you can do something like this.
db.collection.update(
{username : "user1", 'arr.name': {$ne: 'test2'}},
{$push: {
arr: {'name': 'test2', 'times': 0}
}
})
The $ne condition will prevent the update if the name is already present in arr.
You can now use the addToSet operator that is built just for that: adds a value to an array if it does not exist.
Documentation: https://docs.mongodb.com/manual/reference/operator/update/addToSet/
My document structure is as below.
{
"_id" : {
"timestamp" : ISODate("2016-08-27T06:00:00.000+05:30"),
"category" : "marketing"
},
"leveldata" : [
{
"level" : "manager",
"volume" : [
"45",
"145",
"2145"
]
},
{
"level" : "engineer",
"volume" : [
"2145"
]
}
]
}
"leveldata.volume" embedded array document field can have around 60 elements in it.
In this case, "leveldata" is an array document.
And "volume" is another array field inside "leveldata".
We have a requirement to fetch specific elements from the "volume" array field.
For example, elements from specific positions, For Example, position 1-5 within the array element "volume".
Also, we have used positional operator to fetch the specific array element in this case based on "leveldata.level" field.
I tried using the $slice operator. But, it seems to work only with arrays not with array inside array fields, as that
is the case in my scenario.
We can do it from the application layer, but that would mean loading the entire the array element from mongo db to memory and
then fetching the desired elements. We want to avoid doing that and fetch it directly from mongodb.
The below query is what I had used to fetch the elements as required.
db.getCollection('mycollection').find(
{
"_id" : {
"timestamp" : ISODate("2016-08-26T18:00:00.000-06:30"),
"category" : "sales"
}
,
"leveldata.level":"manager"
},
{
"leveldata.$.volume": { $slice: [ 1, 5 ] }
}
)
Can you please let us know your suggestions on how to address this issue.
Thanks,
mongouser
Well yes you can use $slice to get that data like
db.getCollection('mycollection').find({"leveldata.level":"manager"} , { "leveldata.volume" : { $slice : [3 , 1] } } )
MongoDB seems to interpret $set paths with numerical components as object keys rather than array indexes if the field has not already been created as an array.
> db.test.insert({_id: "one"});
> db.test.update({_id: "one"}, {$set: {"array.0.value": "cheese"}});
> db.find({_id: "one"})
{ "_id": "one", "array": { "0" : { "value" : "cheese" } }
I expected to get "array": [{"value": "cheese"}], but instead it was initialized as an object with a key with the string "0".
I could get an array by initializing the whole array, like so:
> db.test.update({_id: "one"}, {$set: {"array": [{"value": "cheese"}]}});
... but this would clobber any existing properties and other array elements that might have been previously set.
Is there any way to convince $set that I want "array" to be an array type, with the following constraints:
I want to execute this in a single query, without looking up the record first.
I want to preserve any existing array entries and object values
In short, I want the behavior of $set: {"array.0.value": ... } if "array" had already been initialized as an array, without knowing whether or not it has. Is this possible?
I am not sure if this is possible without lookup. Perhaps you can change schema design, and try something like this:
db.test.insert({_id: "one"});
db.test.update({_id: "one"}, {$addToSet: {array: { $each:['cheese', 'ham'] }}});
db.test.findOne({_id:'one'});
// { "_id" : "one", "array" : [ "cheese", "ham" ] }
Handling array elements (sub-documents in array) in MongoDb is pain. https://jira.mongodb.org/browse/SERVER-1243
Does Solr maintain sequence of fields (Dynamic fields ) in result document like in the sequence used to index the document ?
For Example:
Consider the following record being indexed
School_txt , Class_txt , Section_txt
So When I will get this document as a result , will the sequence of fields be maintained or it can be random like Class_tx , School_txt , Section_txt ?
If it can be random then how can I preserve the sequence of fields ?
Yes, the sequence of the fields are maintained (at least with 4.9.0) for each document. This is also true for multiValued field, where the values are returned in the same sequence as they are added (which is useful if you want to merge two fields into a separate value later). Here's an example where I rotated the field sequence while indexing:
{
"id": "1",
"School_txt": "School",
"Class_txt": "Class",
"Section_txt": "Section1",
"_version_": 1473987528354693000
},
{
"id": "2",
"Class_txt": "School2",
"Section_txt": "Class2",
"School_txt": "Section2",
"_version_": 1473987528356790300
},
{
"id": "3",
"Section_txt": "School3",
"School_txt": "Class3",
"Class_txt": "Section3",
"_version_": 1473987528356790300
}