MongoDB Index Array only partly working - arrays

I know there is already a lot on this subject out there, but none of the questions do help me going on.
I have a File-Upload-System via GridFS which generates documents like this:
{ "_id" : ObjectId( "4f3723607b5c0b8d01060000" ),
"filename" : "7326_150970547928_746052928_2521002_2164327_n.jpg",
"filetype" : "image/jpeg",
"title" : "Indexed File 1",
"author" : "chewbacca",
"document" : "Rechnungen",
"keywords" : { "0" : "Darth",
"1" : "Vader",
"2" : "Haut",
"5" : "Putz",
"6" : "Pushy" },
"uploadDate" : Date( 1329013600519 ),
"length" : 61423,
"chunkSize" : 262144,
"md5" : "c73cce0bb6f349007635751f9a1a7ddd" }
As you can see I have a field 'keywords' which is an array of keywords.
I want to build a search-option to search this field comparable to a fulltext search.
Therefor I indexed the field 'keywords' seperately.
db.fs.files.ensureIndex({ keywords : 1 })
Now the problem is, that this works sometimes. Or to say yesterday it worked on some files, but on some it won't find anything.
Assuming I did the Indexing like above, I would think that
> db.fs.files.find({keywords : "Vader"})
would give me the document printed above. Or am I missing something??
(My only explanation why this could be, is: it takes a lot of time to create indexes and it ain't ready yet, which is practically impossible right, or that there is some problem with the options 'background', 'dropDups', 'unique' etc...
I tried everything. I dropped the Indexes with;
> db.fs.files.dropIndexes()
And created them again. Always controlling via
> db.fs.files.getIndexes()
But no, I can't get any results...
I also tried to make the indexing via PHP just after I saved the file in the database.
For that I use the following code:
$gridFS->ensureIndex(array('keywords' => 1), array("unique" => true));
Or also without the unique option.
As I said sometimes this works and I can query the keywords, but sometimes I can't. Or some keywords are found, but those of other documents not.
Could it be that indexes ain't made for every document equally???
Please somebody help me on that, I really don't get the issue here!
Thanks already.

I suggest you to use a true array in the keywords:
"keywords" : ["Darth", "Vader", "Haut", "Putz", "Pushy"],
So, the following is expected to work:
db.fs.files.ensureIndex({ keywords : 1 })
db.fs.files.find({keywords : "Vader"})

Related

Mongodb query to find element value type of nested array or object in a field

I have mongodb data model where I have some array fields that contain embedded objects or arrays. I have some inconsistencies in the field in question because I've tweaked my application logic. Initially, my model looked like this:
Initial Setup of Results collection
"competition" : "competition1",
"stats" : [
{
"stat1" : [],
"stat2" : []
}
]
However, I saw that this wasn't the best setup for my needs. So I changed it to the following:
New Setup of Results collection
"competition" : "competition1",
"stats" : [
{
"stat1" : 3,
"stat2" : 2
}
]
My problem now is that documents that have the initial setup cause an error. So what I want is to find all documents that have the initial setup and convert them to have the new setup.
How can I accomplish this in mongodb?
Here is what I've tried, but I'm stuck...
db.getCollection('results').find({"stats.0": { "$exists": true }})
But what I want is to be able to do something like
db.getCollection('results').find({"stats.0".stat1: { "$type": Array}})
Basically I want to get documents where the value of stats[0].stat1 is of type array and override the entire stats field to be an empty array.
This would fix the errors I'm getting.
$type operator for arrays in older versions works little differently than what you might think than $type in 3.6.
This will work in 3.6
db.getCollection('results').find( { "stats.0.stat1" : { $type: "array" } } )
You can do it couple of ways for lower versions and It depends what you are looking for.
For empty arrays you can just check
{"stats.0.stat1":{$size:0}}
For non empty arrays
{"stats.0.stat1": {$elemMatch:{ "$exists": true }}}
Combine both using $or for finding both empty and non empty array.
For your use case you can use below update
db.getCollection('results').update({"stats.0.stat1":{$size:0}}, {$set:{"stats":[]}})

Why I dont see array's element when I do db.collection.find()?

I've got a mongo model like this:
attributes:[String]
But when I do : db.ads.find({})
I've got this:
{ "_id" : ObjectId("5571fe998f6319ed03235522"), "attributes" : [ ], "__v" : 0 }
I don't see the elements in the array "attributes" even if actually the array contains this: ["Meublé","Wi-Fi","Salle de sport"]
I would like to be able to do a command like db.ads.find({}) and see the element inside the array
Thanks
Are you doing this in the terminal or your code?
If you are using the terminal:
Use----> db.ads.find()
OR---> db.ads.find().pretty()
to make it look good
Please try to execute in your console the following query:
db.ads.find({"attributes": { $not: { $size: 0 } } })
in order to find all documents that have non-empty "attributes" array.
In your case it looks like you might have many documents with this array empty and db.ads.find() returns a cursor which shows in your console only 20 elements in each iteration (by default), so in first iteration you may be seeing only those that have no values in "attributes".
Hope this will help a little.

Referencing arrays that are nested within multiple objects within MongoDB with Express js

So in my MongoDB Collection I have this structure:
"_id" : "Object("-----------")
"name" : "John Doe"
"tool" : {
"hammer" : {
"name" : "hammer 1",
"characteristics" : [
{
"length" : "9 inches"
},
{
"weight" : "4 pounds"
}
]
I know the data may seem a little strange but I can't put the actual data online so I had to input some dummy data. So essentially what I would like to do is be able to update the array that is nested within those objects. So I would like to be able to update the weight or add a new characteristic that I haven't previously entered into it. So for example, add in "metal" : "steel" as a new entry into the array. Currently I'm using a Rest API built in Node.js and Express.js to edit the db. When I was trying to figure out how to dig down this deep I was able to do it with an array at the highest level, however I haven't been able to figure out how to access an array when its embedded like this. So what I was wondering if anybody knew if it was even possible to edit an array this far down? I can post code from controller.js and server.js file if needed but I figured I'd see if it's even possible to do before I start posting it. Any help would be greatly appreciated!
You can use findAndModify to $push it into the array. You have to specify the path precisely though:
db.tools.findAndModify( {
query: { name: "John Doe"},
update: { $push: { tool.hammer.characteristics: {metal: "steel"} }
} );

MongoDB - Pull from array of objects

I have a collection
{
"_id" : ObjectId("534bae30bf5049a522e502fe"),
"data" : [
{
"0" : {
"content" : "1",
"type" : "text",
"ident" : true
},
"1" : {
"content" : "",
"type" : "text",
"ident" : false
}
},
{
"0" : {
"content" : "2",
"type" : "text",
"ident" : true
},
"1" : {
"content" : "",
"type" : "text"
}
}
]
}
content is unique.
How would i remove the object that matches content: '2'?
I have tried this:
data:{$pull:{"content": deletions[i]}}
where deletions [i] is the content.
and several variations, but i can not get it to work. What am I missing?
As per you comment, you should be worried. I have seen this a few times particularly with PHP applications ( and PHP has this funny kind of notation in dumping arrays ).
The problem is the elements such as the "0" and "1" create sub-documents in themselves, and as opposed to just leaving everything under that structure as the sub-document in itself as the the array member then you run into a problem with accessing individual members of the array as the paths used need to be "absolute".
So this actually "forces" no other possible option to access the elements by what would be the equivalent "dot notation" form. Except in this case it's not just the "nth" element of the array, but the actual path you need to address.
But if this does actually work for you, and it does seem like "someone" was trying to avoid
the problems with positional updates under "nested" arrays ( see the positional $ operator documentation for details ) then you update can be performed like this:
The basic statement is as follows:
db.collection.update(
{
"data.0.context": 2
},
{
"$pull": { "data.$.0.context": 2 }
}
)
That does "seem" to be a bit of a funny way to write this, but on investigating the actual structure you have then you should be able to see the reasons why this is needed. Essentially this meets the requirements of using the positional $ operator to indicate the index of the first matched element in the array ( aka "data" ) and then uses the standard sub-document notation in order to specify the path to the element to be updated.
So of course this poses a problem if the element is actually in an unknown position. But the thing to consider is which usage of the array is actually important to you given the documented limitation? If yo need to match the position of the "inner" element, then change the structure to put the arrays in there.
But always understand the effects of the limitation, and try to model according to what the engine can actually do.

Mongo query item from subarray, having trouble

I'm relatively new to mongodb, and I came into this company's set up that had the database already set up and running. It looks to me like the structure of this "array" isn't actually a proper array. They are saving info that I need in "offer_info_array" - which then has a nested array with an "offer id" which changes a lot between records, and then nested inside that is the info that I need to select. Here is an example of a record.
{
"_id" : ObjectId("52041af3bbf8057203000004"),
"offer_info_array" : {
"128" : {
"affid" : "68",
"s1" : "YJF"
}
},
"city" : "Cleveland",
"state" : "OH",
"zip" : "44111"
}
So from a whole db of records like this one, I need to find all records that have the "affid" of "68" - I realize this database is not structured correctly, but there's not much I can do about that for records that already exist. The "128" is the offer id that varies from record to record.
If anyone has any insight and can help me out with this, I would greatly appreciate it. Thank you!
You can use $where operator which accepts JavaScript function:
db.items.find({$where: function() {
for(var key in obj.offer_info_array)
if(obj.offer_info_array[key].affid == 68)
return true;
return false; }})
This function looks for properties of offer_info_array object and gets value of property by key. Then we verify if property value has affid property equal to 68. If yes, we return true which means objects matches our query. If there is no properties with affid equal to 68, we return false.
Keep in mind, that $where operator do not use indexes.

Resources