ELASTICSEARCH - Update the value of a field to current date - date

I'm looking for a way to update the value of a field through update_by_query in the field: reviewed_data in the next document:
{
"reviewed_date" : "2022-07-05T09:31:04.742077702Z",
"timestamp" : "2022-07-05T10:18:52.353852943Z"
}
I'm doing it through the following way:
POST index1/_update_by_query
{
"script": {
"source": "ctx._source.reviewed_date = OffsetDateTime.parse(ctx._source.reviewed_date)" ,
"lang": "painless"
},
"query": {
"term": {
"_id": "23r2fvwc3drgr4f2323dsd"
}
}
}
This way I only manage to update the value of the timestamp date, even though I am indicating reviewed_date.
But I would like to be able to assign the value directly to reviewed_data without modifying other fields.
Mapping:
"timestamp" : {
"type" : "date"
}
"reviewed_date" : {
"type" : "date"
},

Related

Mongo remove from nested object by value

I have a Mongo collection the consists of a document and a nested object describing what collections the document is in and when it was added. I would like to remove key-value pairs from a nested object based on a condition, e.g. is the value (a date) before 1-1-2016.
Example:
{
"_id" : ObjectId("581214940911ad3de98002db"),
"collections" : {
"c01" : ISODate("2016-10-27T15:52:04.512Z"),
"c02" : ISODate("2015-11-21T16:06:06.546Z")
}
}
needs to become
{
"_id" : ObjectId("581214940911ad3de98002db"),
"collections" : {
"c01" : ISODate("2016-10-27T15:52:04.512Z"),
}
}
One alternative would be to change the schema to something like this:
{
"_id" : ObjectId("581214940911ad3de98002db"),
"collections" : [
{
"id": "c01",
"date": ISODate("2016-10-27T15:52:04.512Z")
},
{
"id": "c02",
"date" : ISODate("2015-11-21T16:06:06.546Z")
}
]
}
in which case removing a document from a would be easy. I am a bit reluctant to do that because it would complicate some of the other queries I would like to support. Thanks!
I prefer the second structure for your schema
{
"_id" : ObjectId("581214940911ad3de98002db"),
"collections" : [
{
"id": "c01",
"date": ISODate("2016-10-27T15:52:04.512Z")
},
{
"id": "c02",
"date" : ISODate("2015-11-21T16:06:06.546Z")
}
]
}
then able to remove from collections like this
db.collectionName.update(
{ },// if you want can add query for specific Id {"_id" : requestId},
{ $pull: { collections: { date: {$lt: yourDate} } } }, // if need can convert iso date string like: new Date(yourDate).toISOString()
{ multi: true }
)

Retrieving value of an emedded object in mongo

Followup Question
Thanks #4J41 for your spot on resolution. Along the same lines, I'd also like to validate one other thing.
I have a mongo document that contains an array of Strings, and I need to convert this particular array of strings into an array of object containing a key-value pair. Below is my curent appraoch to it.
Mongo Record:
Same mongo record in my initial question below.
Current Query:
templateAttributes.find({platform:"V1"}).map(function(c){
//instantiate a new array
var optionsArray = [];
for (var i=0;i< c['available']['Community']['attributes']['type']['values'].length; i++){
optionsArray[i] = {}; // creates a new object
optionsArray[i].label = c['available']['Community']['attributes']['type']['values'][i];
optionsArray[i].value = c['available']['Community']['attributes']['type']['values'][i];
}
return optionsArray;
})[0];
Result:
[{label:"well-known", value:"well-known"},
{label:"simple", value:"simple"},
{label:"complex", value:"complex"}]
Is my approach efficient enough, or is there a way to optimize the above query to get the same desired result?
Initial Question
I have a mongo document like below:
{
"_id" : ObjectId("57e3720836e36f63695a2ef2"),
"platform" : "A1",
"available" : {
"Community" : {
"attributes" : {
"type" : {
"values" : [
"well-known",
"simple",
"complex"
],
"defaultValue" : "well-known"
},
[......]
}
I'm trying to query the DB and retrieve only the value of defaultValue field.
I tried:
db.templateAttributes.find(
{ platform: "A1" },
{ "available.Community.attributes.type.defaultValue": 1 }
)
as well as
db.templateAttributes.findOne(
{ platform: "A1" },
{ "available.Community.attributes.type.defaultValue": 1 }
)
But they both seem to retrieve the entire object hirarchy like below:
{
"_id" : ObjectId("57e3720836e36f63695a2ef2"),
"available" : {
"Community" : {
"attributes" : {
"type" : {
"defaultValue" : "well-known"
}
}
}
}
}
The only way I could get it to work was with find and map function, but it seems to be convoluted a bit.
Does anyone have a simpler way to get this result?
db.templateAttributes.find(
{ platform: "A1" },
{ "available.Community.attributes.type.defaultValue": 1 }
).map(function(c){
return c['available']['Community']['attributes']['type']['defaultValue']
})[0]
Output
well-known
You could try the following.
Using find:
db.templateAttributes.find({ platform: "A1" }, { "available.Community.attributes.type.defaultValue": 1 }).toArray()[0]['available']['Community']['attributes']['type']['defaultValue']
Using findOne:
db.templateAttributes.findOne({ platform: "A1" }, { "available.Community.attributes.type.defaultValue": 1 })['available']['Community']['attributes']['type']['defaultValue']
Using aggregation:
db.templateAttributes.aggregate([
{"$match":{platform:"A1"}},
{"$project": {_id:0, default:"$available.Community.attributes.type.defaultValue"}}
]).toArray()[0].default
Output:
well-known
Edit: Answering the updated question: Please use aggregation here.
db.templateAttributes.aggregate([
{"$match":{platform:"A1"}}, {"$unwind": "$available.Community.attributes.type.values"},
{$group: {"_id": null, "val":{"$push":{label:"$available.Community.attributes.type.values",
value:"$available.Community.attributes.type.values"}}}}
]).toArray()[0].val
Output:
[
{
"label" : "well-known",
"value" : "well-known"
},
{
"label" : "simple",
"value" : "simple"
},
{
"label" : "complex",
"value" : "complex"
}
]

Need help to search document with random field names

I looked through the MongoDB documentation and googled this question but couldn't really find a suitable answer.
encounter a problem where I need to search documents in a collection, but 3 fields name will change from one doc to another even though they are always at the same positions.
In the following example, the 366_DAYS can be 2_HOURS, 35_DAYs etc from document to document, but they will be in the same position.
The _XC4ucB8sEeSybaax341rBg will change to another random string from doc to doc, again it will be at the same position for all docs.
Other fields do not change name and stay at the same position.
I want a query to search for records where debitAmount >=creditAmount or endDate > now().
set02:PRIMARY> db.account.find({ _id: "53e51b1b0cf22cb159fa5f38" }).pretty()
{
"_id" : "53e51b1b0cf22cb159fa5f38",
"_version" : 6,
"_transId" : "e3e96377-a2d2-4b75-a946-f621df182c5e-2719",
"accountBalances" : {
"TEST_TIME" : {
"thresholds" : {
},
"deprovisioned" : false,
"quotas" : {
"366_DAYS" : {
"thresholds" : {
},
"quotaCode" : "366_DAYS",
"credits" : {
"_XC4ucB8sEeSybaax341rBg" : {
"startDate" : ISODate("2014-08-08T18:46:51.351Z"),
"creditAmount" : "86460",
"endDate" : ISODate("2014-08-09T18:48:19Z"),
"started" : true,
"debits" : {
"consolidated" : {
"creationDate" : ISODate("2014-08-08T19:15:55.396Z"),
"debitAmount" : "1300",
"debitId" : "consolidated"
}
},
"creditId" : "_XC4ucB8sEeSybaax341rBg"
}
}
}
},
"expiredReservations" : {
},
"accountBalanceCode" : "TEST_TIME",
"reservations" : {
}
}
},
"subscriberId" : "53e51b1b0cf22cb159fa5f38"
}
Can you use arrays for quotas and credits? That would make the path be the same.
"quotas": [
{
"days": 365,
"thresholds": {},
"credits": [
{
"id": "_XC4ucB8sEeSybaax341rBg"
}
]
}
]
Two cases come to mind. Which one applies to you is unclear to me from the question so providing for both possibilities.
CASE 1:
You will always have either 366_DAYS, 2_HOURS or 35_DAYS inside quotas and only one possible creditId per document. If this is the case, then why replicate the quotaCode and the creditId both as a sub-field and as the key inside quotas and credits respectively. You could alter the structure of your document as follows:
{
"_id": "53e51b1b0cf22cb159fa5f38",
"_version": 6,
"_transId": "e3e96377-a2d2-4b75-a946-f621df182c5e-2719",
"accountBalances": {
"TEST_TIME": {
"thresholds": {},
"deprovisioned": false,
"quotas": {
"thresholds": {
},
"quotaCode": "366_DAYS",
"credits": {
"startDate": ISODate("2014-08-08T18:46:51.351Z"),
"creditAmount": "86460",
"endDate": ISODate("2014-08-09T18:48:19Z"),
"started": true,
"debits": {
"consolidated": {
"creationDate": ISODate("2014-08-08T19:15:55.396Z"),
"debitAmount": "1300",
"debitId": "consolidated"
}
},
"creditId": "_XC4ucB8sEeSybaax341rBg"
}
},
"expiredReservations": {
},
"accountBalanceCode": "TEST_TIME",
"reservations": {
}
}
},
"subscriberId": "53e51b1b0cf22cb159fa5f38"
}
Now the fieldPath for fields in your queries would be:
"accountBalances.TEST_TIME.quotas.credits.creditAmount"
"accountBalances.TEST_TIME.quotas.credits.debits.consolidated.debitAmount"
"accountBalances.TEST_TIME.quotas.credits.startDate"
CASE 2:
quotas and credits may contain more than one subdocument. In this case viktortnk's approach of having quotas and credits as arrays will work. The fieldPath for your queries may then be written as:
"accountBalances.TEST_TIME.quotas.[zero-base-index].credits.[zero-base-index].creditAmount"
"accountBalances.TEST_TIME.quotas.[zero-base-index].credits.[zero-base-index].debits.consolidated.debitAmount"
"accountBalances.TEST_TIME.quotas.[zero-base-index].credits.[zero-base-index].startDate"

Modify a document inside an array in MongoDB

Past answers (from mid 2013 and before) don't seem to work and links to the documentation are all out of date.
Example user object:
{
"name": "Joe Bloggs",
"email": "joebloggs#example.com",
"workstations" : [
{ "number" : "10001",
"nickname" : "home" },
{ "number" : "10002",
"nickname" : "work" },
{ "number" : "10003",
"nickname" : "vacation" }
]
}
How can I modify the nickname of a workstation?
I tried using $set, workstations.$ and workstations.nickname but none gave the desired results.
Short answer, you have to use array index. For example, you want to update the nickname of 10002: {$set:{"workstations.1.nickname":"newnickname"}}
Here is the complete example:
> db.test.update({"_id" : ObjectId("5332b7cf4761549fb7e1e72f")},{$set:{"workstations.1.nickname":"newnickname"}})
> db.test.findOne()
{
"_id" : ObjectId("5332b7cf4761549fb7e1e72f"),
"email" : "joebloggs#example.com",
"name" : "Joe Bloggs",
"workstations" : [
{
"number" : "10001",
"nickname" : "home"
},
{
"nickname" : "newnickname",
"number" : "10002"
},
{
"number" : "10003",
"nickname" : "vacation"
}
]
}
>
If you don't know the index (position of the workstations), you can update the doc using $elemMatch:
>db.test.update(
{
"email": "joebloggs#example.com",
"workstations": { "$elemMatch" { "number" : "10002" } }
},
{
"$set": { "workstations.$.nickname": "newnickname2" }
}
)
>
#naimdjon's answer would work. To generalize, you could use the $elemMatch operator in combination with the $ positional operator to update one element in the array using below query:
db.test.update({
// Find the document where name="Joe Bloggs" and the element in the workstations array where number = "10002"
"name": "Joe Bloggs",
"workstations":{$elemMatch:{"number":"10002"}}
},
{
// Update the nickname in the element matched
$set:{"workstations.$.nickname":"newnickname"}
})
Note: $elemMatch is only required if you need to match more than one component in the array. If you are going to match on just the number, you could use "workstations.number":"10002"
As long as you know "which" entry you wish to update then the positional $ operator can be of help. But you need to update your query form:
db.collection.update(
{
"email": "joebloggs#example.com",
"workstations": { "$elemMatch" { "nickname" : "work" } }
},
{
"$set": { "workstations.$.nickname": "new name" }
}
)
So that is the general form. What you need to do here is "match" something in the array in order to get a "position" to use for the update.
Alternately, where you know the position, then you can just "specify" the position with "dot notation":
db.collection.update(
{
"email": "joebloggs#example.com",
},
{
"$set": { "workstations.1.nickname": "new name" }
}
)
Which updates the second element in the array, and does not need the "matching" part in the query.

ElasticSearch - pagination of date histogram results

Is it possible to paginate results from a date histogram?
I have the following example date histogram, but using the "from" : 0, "size" : 10 parameters do not seem to work.
POST _search/
{
"query" : {
"match_all" : {}
},
"facets" : {
"histo1" : {
"date_histogram" : {
"value_field": "value.count",
"interval" : "10s",
"field": "_timestamp"
}
}
}
}
The "from" and "size" parameters work only with results of your query (hits). Facets run on the entire result list regardless of how many records you choose to retrieve. Therefore, in order to implement "pagination" on histogram, you need to limit your query. For example, in order to retrieve all histogram buckets for the last hour you can simply add range query or filter to you query that will limit results to the current hour. If _timestamp is indexed as date, you can do something like this:
POST _search/
{
"query" : {
"filtered": {
"query": {
"match_all" : {}
},
"filter": {
"range" : {
"_timestamp" : {
"gt": "now-1h",
"lte": "now"
}
}
}
}
},
"facets" : {
"histo1" : {
"date_histogram" : {
"value_field": "value.count",
"interval" : "10s",
"field": "_timestamp"
}
}
}
}