How to apply $lt to array elements? - mongodb

I'm trying this (all documents have tags array):
db.find($lt: ['$tags.0.created', '2019-05-05'])
I want to fetch all documents where the first tag was created before the specified date. It doesn't work. I mean, it returns all elements. What's wrong in this query?

The actual find would look something like this:
db.YOURCOLLECTION.find({ 'tags.0.created': { $lt: '2019-05-05' } })
You can see it working here

Related

Is there a way to update array value in algolia Partial Update Method?

My records are something like this,
{
objectID: "123123",
product_id: "456456",
categories: ['pie', 'desert']
}
I want to just replace desert with sweet in categories.
Is this possible by using partial_update_objects method?
You can't update a value but ultimately you can Remove & Add with the built-in operations. It would allow an "update" of the value (it only works if the values in the array are unique). An alternative is to get the object and compute the new value for the array to later replace it.

Updating multiple complex array elements in MongoDB

I know this has been asked before, but I have yet to find a solution that works efficiently. I am working with the MongoDB C# driver, though this is more of a general question about MongoDB operations.
I have a document structure that looks something like this:
field1: value1
field2: value2
...
users: [ {...user 1 subdocument...}, {...user 2 subdocument...}, ... ]
Some facts:
Each user subdocument includes further sub-arrays & subdocuments (so they're fairly complex).
The average users array only contains about 5 elements, but in the worst case can surpass 100.
Several thousand update operations on multiple users may be conducted per day in this system, each on one document at a time. Larger arrays will receive more frequent updates due to their data size.
I am trying to figure out how to do this efficiently. From what I've heard, you cannot directly set several array elements to new values all at once, so I had to try something else.
I tried using the $pullAll / $AddToSet + $each operations to remove the old array and replace it with a modified one. I am aware that $pullall can remove only the elements that I need as well, but I would like to preserve the order of elements.
The C# code:
try
{
WriteConcernResult wcr = collection.Update(query,
Update.Combine(Update.PullAll("users"),
Update.AddToSetEach("users", newUsers.ToArray())));
}
catch (WriteConcernException wce)
{
return wce.Message;
}
In this case newUsers is aList<BsonValue>converted to an array. However I am getting the following exception message:
Cannot update 'users' and 'users' at the same time
By the looks of it, I can't have two update statements in use on the same field in the same write operation.
I also tried Update.Set("users", newUsers.ToArray()), but apparently the Set statement doesn't work with arrays, just basic values:
Argument 2: cannot convert from 'MongoDB.Bson.BsonValue[]' to 'MongoDB.Bson.BsonValue'
So then I tried converting that array to a BsonDocument:
Update.Set("users", newUsers.ToArray().ToBsonDocument());
And got this:
An Array value cannot be written to the root level of a BSON document.
I could try replacing the whole document, but that seems like overkill and definitely not very efficient.
So the only thing I can think of now is to run two separate write operations: one to remove the unwanted old users and another to replace them with their newer versions:
WriteConcernResult wcr = collection.Update(query, Update.PullAll("users"));
WriteConcernResult wcr = collection.Update(query, Update.AddToSetEach("users", newUsers.ToArray()));
Is this my best option? Or is there another, better way of doing this?
Your code should work with a minor change:
Update.Set("users", new BsonArray(newUsers));
BsonArray is a BsonValue, where as an array of documents is not and we don't implicitly convert arrays like we do other primitive values.
this extension method solve my problem:
public static class MongoExtension
{
public static BsonArray ToBsonArray(this IEnumerable list)
{
var array = new BsonArray();
foreach (var item in list)
array.Add((BsonValue) item);
return array;
}
}

Mongo find by regex: return only matching string

My application has the following stack:
Sinatra on Ruby -> MongoMapper -> MongoDB
The application puts several entries in the database. In order to crosslink to other pages, I've added some sort of syntax. e.g.:
Coffee is a black, caffeinated liquid made from beans. {Tea} is made from leaves. Both drinks are sometimes enjoyed with {milk}
In this example {Tea} will link to another DB entry about tea.
I'm trying to query my mongoDB about all 'linked terms'. Usually in ruby I would do something like this: /{([a-zA-Z0-9])+}/ where the () will return a matched string. In mongo however I get the whole record.
How can I get mongo to return me only the matched parts of the record I'm looking for. So for the example above it would return:
["Tea", "milk"]
I'm trying to avoid pulling the entire record into Ruby and processing them there
I don't know if I understand.
db.yourColl.aggregate([
{
$match:{"yourKey":{$regex:'[a-zA-Z0-9]', "$options" : "i"}}
},
{
$group:{
_id:null,
tot:{$push:"$yourKey"}
}
}])
If you don't want to have duplicate in totuse $addToSet
The way I solved this problem is using the string aggregation commands to extract the StartingIndexCP, ending indexCP and substrCP commands to extract the string I wanted. Since you could have multiple of these {} you need to have a projection to identify these CP indices in one shot and have another projection to extract the words you need. Hope this helps.

Find All Objects Created Before Specified Date

Mongo has a nice feature that tells you when a document was created.
ObjectId("53027f0adb97425bbd0cce39").getTimestamp() = ISODate("2014-02-17T21:28:42Z")
How would I get about finding all documents that were created before lets say February 10th 2014? Searched around but doesn't seem like this question comes up. Any help is appreciated! Thanks!
You mean something like this?
db.YOUR_COLLECTION.find({YOUR_DATE_FIELD: { "$lt": ISODate("2014-02-10") }})
Guess that you have to make the same as JoJo recommended:
Convert a date to an ObjectId
Filter ID using $lt and returned ObjectId
Using pymongo you can do something like this:
gen_time = datetime.datetime(2014, 2, 10)
dummy_id = ObjectId.from_datetime(gen_time)
result = collection.find({"_id": {"$lt": dummy_id}})
Reference: http://api.mongodb.org/python/1.7/api/pymongo/objectid.html

meteor iterate through array

here is my collection
Ques_Coll.insert({question: quest,owner:u_name,comments:[]});
After user enters comment, collection will be updated like this
Ques_Coll.update({_id:this._id},{$push:{comments:{uname:"xxx",cmt_text:"xxx"}}});
Until this working fine
Now, i want to iterate through all the comments and want to display them
how to do it?
this is how i tried and not working
{{#each all_comments.comments}}
<li>{{uname}}</li>
<li>{{cmt_text}}</li>
{{/each}}
this is my template //i think my problem lies in this returning value
all_comments:function()
{
return Ques_Coll.find( {_id:this._id},{fields: {'comments': 1}})
}
Use findOne instead:
Ques_Coll.findOne( {_id:this._id},{fields: {'comments': 1}})
You use find when you're searching for more than one question to match the criteria. But since you're looking for one (the one with the comments), you use findOne instead.