MongoDB convert BsonTimestamp to Date - mongodb

Is there an (efficient) way of converting a MongoDB document field with of type BsonTimestamp to a Date field. Do I have to create a temporary field to store the Date. Do I have to write a custom JS migartion script and loop over every item for this?
from this:
"ts": {
"$timestamp": {
"t": 1620986905,
"i": 1
}
}
to this:
"ts": {
"$date": {
"$numberLong": "1620986905626"
}
}

Related

MongoDB Rust Driver weird behavior

There is this weird thing,
I have installed the MongoDB Compass and made a aggregation query that works in the Aggregation tab but now when I use the same query in my rust web server it behaves very weirdly
Original message:
{"_id":{"$oid":"61efd41c56ffe6b1b4a15c7a"},"time":{"$date":"2022-01-25T10:42:36.175Z"},"edited_time":{"$date":"2022-01-30T14:29:54.361Z"},"changes":[],"content":"LORA","author":{"$oid":"61df3cab3087579f8767a38d"}}
Message in MongoDB compass after the query:
{
"_id": {
"$oid": "61efd41c56ffe6b1b4a15c7a"
},
"time": {
"$date": "2022-01-25T10:42:36.175Z"
},
"edited_time": {
"$date": "2021-12-17T09:55:45.856Z"
},
"changes": [{
"time": {
"$date": "2021-12-17T09:55:45.856Z"
},
"change": {
"ChangedContent": "LORA"
}
}],
"content": "LMAO",
"author": {
"$oid": "61df3cab3087579f8767a38d"
}
}
Message after the Web Servers query:
{
"_id": {
"$oid": "61efd41c56ffe6b1b4a15c7a"
},
"time": {
"$date": "2022-01-25T10:42:36.175Z"
},
"edited_time": {
"$date": "2022-01-30T14:40:57.152Z"
},
"changes": {
"$concatArrays": ["$changes", [{
"time": {
"$date": "2022-01-30T14:40:57.152Z"
},
"change": {
"ChangedContent": "$content"
}
}]]
},
"content": "LMAO",
"author": {
"$oid": "61df3cab3087579f8767a38d"
}
}
Pure query in MongoDB Compass:
$set stage
{
"changes": { $concatArrays: [ "$changes", [ { "time": ISODate('2021-12-17T09:55:45.856+00:00'), "change": { "ChangedContent": "$content" } } ] ] },
"edited_time": ISODate('2021-12-17T09:55:45.856+00:00'),
"content": "LMAO",
}
Pure query in Web Server:
let update_doc = doc! {
"$set": {
"changes": {
"$concatArrays": [
"$changes", [
{
"time": now,
"change": {
"ChangedContent": "$content"
}
}
]
]
},
"edited_time": now,
"content": content
}
};
I am using update_one method,
like this
messages.update_one(message_filter, update_doc, None).await?;
I don't really understand, and this happens often, sometimes it fixes it self when I add somewhere randomly some scope in the doc eg.: { } but this time I couldn't figure it out,
I had version of the query with $push but that didn't work too
Is there some fault in the rust driver or am I doing something wrong, are there some rules about formatting when using rust driver that I am missing?
The $set aggregation pipeline stage is different from the $set update operator. And the only difference that I can tell, is the pipeline stage handles $concatArrays while the update operator does not.
$set Aggregation Pipeline Stage
$set appends new fields to existing documents. You can include one or more $set stages in an aggregation operation.
To add field or fields to embedded documents (including documents in arrays) use the dot notation.
To add an element to an existing array field with $set, use with $concatArrays.
$set Update Operator
Starting in MongoDB 5.0, update operators process document fields with
string-based names in lexicographic order. Fields with numeric names
are processed in numeric order.
If the field does not exist, $set will add a new field with the
specified value, provided that the new field does not violate a type
constraint. If you specify a dotted path for a non-existent field,
$set will create the embedded documents as needed to fulfill the
dotted path to the field.
If you specify multiple field-value pairs, $set will update or create
each field.
So if you want to update an existing document by inserting elements into an array field, use the $push update operator (potentially with $each if you're inserting multiple elements):
let update_doc = doc! {
"$set": {
"edited_time": now,
"content": content
},
"$push": {
"changes": {
"time": now,
"change": {
"ChangedContent": "$content"
}
}
}
};
Edit: I missed that $content was supposed to be mapped from the existing field as well. That is not supported by an update document, however MongoDB has support for using an aggregation pipeline to update the document. See: Update MongoDB field using value of another field So you can use the original $set just in a different way:
let update_pipeline = vec![
doc! {
"$set": {
"changes": {
"$concatArrays": [
"$changes", [
{
"time": now,
"change": {
"ChangedContent": "$content"
}
}
]
]
},
"edited_time": now,
"content": content
}
}
];
messages.update_one(message_filter, update_pipeline, None).await?;

Move data from inside nested array

I have inserted multiple documents in my Mongo database incorrectly. I have accidentally nested the data inside another data object:
{
"_id": "5cdfda8ddc5cf00031fd3949",
"payload": {
"timestamp": "2019-05-18T10:12:29.896Z",
"data": {
"data": {
"name": 10,
"age": 10,
}
}
},
"__v": 0
}
I would like the document to not have the extra data object. So I would like it to look like this:
{
"_id": "5cdfda8ddc5cf00031fd3949",
"payload": {
"timestamp": "2019-05-18T10:12:29.896Z",
"data": {
"name": 10,
"age": 10,
}
},
"__v": 0
}
Is there a way in Mongo for me to update all the documents that have 2 data objects to just have one like shown above?
Alas, you cannot do this with one database request. You have to loop over all documents programmatically, set the new data and update them in the database.
You could use the aggregation framework, which won't let you update in place, but you could use the $out operator to write the results to a new collection, if that's an option.
db.collection.aggregate([
{
$project: {
__v : 1,
"payload.timestamp" : 1,
"payload.data" : "$payload.data.data"
},
},
{
"$out": "newCollection"
}
])
Or if you have a mixture of docs with correct format and docs with incorrect format, you can use the $cond operator to determine the correct output:
db.collection.aggregate([
{
$project: {
__v : 1,
"payload.timestamp" : 1,
"payload.data" : {
$cond: [
{ $ne : [ "$payload.data.data", undefined]},
"$payload.data.data",
"$payload.data"
]}
}
},
{
"$out": "newCollection"
}
])

How to query based on nested object's key and value?

"session": {
"number": 123,
"words": {
"1": {
"id": 10,
"name": "Hello"
},
"2": {
"id": 13,
"name": "Hi"
},
"3": {
"id": 135,
"name": "Hey"
}
}
}
We have data in MongoDB database in the given structure which I am not able to modify.
I can get the object based on query session.number is 123, but now the challenging is we know the nested name is either Hi, Hey or Hello but the incremental key inside object words are unpredictable, is it possible to query base on the "name" field?
You can use $objectToArray and convert the words property to an array then query it however you want, you can use the following:
collection.aggregate([
{
$project: {
words: { $objectToArray: "$session.words" }
}
},
{
$match: {
'words.v': 'hi'
}
}
]);
You can read the docs for more info.

Mongodb: Unsupported conversion from array to objectId in $convert with no onError value

I use mongodb 4.0.5. I'm using lookup to join two collections, the foreign key is a string value located in request_by array and the other one is
ObjectId
{
$addFields: {
convertedId: {
$toObjectId: "$request_by.userId"
}
}
}
i want to convert the foreign key to ObjectId so i can join them. But it says "Unsupported conversion from array to objectId in $convert with no onError value"
i have a data something like this:
Simulation collection
{
"_id": "8f361e8969948e1c435c06d7",
"request_by": [{
"userId": "ae83ccfa592f4963a395263c",
"iat": 1544801930,
"exp": 1544819930
}],
"status": "finish",
"start": "2018-12-14T15:39:29.588Z",
"end": "2018-12-14T16:59:29.538Z",
"duration": 80,
"passing_grade": 100,
"created_at": "2018-12-14T15:39:29.588Z",
"updated_at": "2018-12-14T15:43:12.897Z",
"__v": 0
}
How i can join them if i have data like that?
You need $map since request_by is an array, then you can pass that array directly into $lookup (joins single fields or arrays).
{
$addFields: {
convertedId: {
$map: {
input: "$request_by",
as: "r",
in: { $toObjectId: "$$r.userId" }
}
}
}
}

How to write query for date in mongolab?

i have stored data like this
"C_Newsletter": {
"date": {
"$date": "2015-10-20T09:52:26.498Z"
}
},
For this how can i write query for date search in mongolab.here i want to search
2015-10-20 .where ever 2015-10-20 matches i need to show
i am new to mongo lab some one help me out for this.i have written like this
{
"C_Newsletter": {
"date": {
"$date": "2015-10-20T09:52:26.498Z"
}
}
}
but its showing only one data .becoz of exact time and date.my expectation i want to get entire 2015-10-20 data
Create a date range query using the $gt and $lte operators where you search for dates between a particular range i.e. end of previous day to end of day in question, something like the following:
{
"C_Newsletter": {
"date": {
"$gt": { "$date": "2015-10-19T23:59:59.999Z" },
"$lte": { "$date": "2015-10-20T23:59:59.999Z" }
}
}
}