I am trying to update nested object using mongoose. I am trying to update the "remindTime date" only and keep the "time" I can update the "remindTime date" however it erases my "remindTime time" property.
I have try the following and none of them work
Model.updateMany(req.query, { remindTime: { date: "2021-09-28" } })
Model.updateMany(req.query, { remindTime: $set:{ { date: "2021-09-28" } } } )
Database data that I am updating
{
"_id": {
"$oid": "614d3cedfb2600340fdb28f9"
},
"date": "2021-09-23",
"title": "First test",
"description": "not working yet",
"remindTime": {
"date": "2021-09-28",
"time": "01:20 am"
},
"isComplete": false,
}
Please try this:
Model.updateMany(req.query, { "remindTime.date": "2021-09-28"})
You can use dot notation:
According to docs:
MongoDB uses the dot notation to access the elements of an array and to access the fields of an embedded document.
To specify or access a field of an embedded document with dot notation, concatenate the embedded document name with the dot (.) and the field name, and enclose in quotes:
"<embedded document>.<field>"
So the query:
Model.updateMany(req.query,
{
"$set": {
"remindTime.date": "new date"
}
})
Example here
Related
sample data for title
actiontype test
booleanTest
test-demo
test_demo
Test new account object
sync accounts data test
default Mapping for title
"title": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
tried with this query search
{
"query": {
"bool": {
"must": [
{
"match": {
"title": "test"
}
}
]
}
},
}
here my expectation
with specific word(e.g. : test ) it should return following titles
expect
actiontype test
booleanTest
test-demo
test_demo
Test new account object
sync accounts data test
But
got
actiontype test
test-demo
test_demo
Test new account object
sync accounts data test
With exact match (e.g. : sync accounts data test ) it should return only this(sync accounts data test) but got all records those contains this words (sync,account,data,test).
What should I do to make this happen ? Thanks.
I am not sure which ES version you're using but the following should give you an idea.
Using your mapping you can get all title text with test, including booleanTest using query string query type. Eg.
GET {index-name}/{mapping}/_search
{
"query": {
"query_string": {
"default_field": "title",
"query": "*test*"
}
}
}
However, for this to work, make sure you give your title field an analyzer with a lowercase analyzer filter (see below settings example). Your current mapping will not work since it's just pure text as is... test /= TEST by default.
There are other ways, if you're interested to know the workings of ES... Eg. You can also match booleanTest in your match query by writing a custom nGram filter to your index settings. Something like,
{
"index": {
"settings": {
"index": {
"analysis": {
"filter": {
"nGram": {
"type": "nGram",
"min_gram": "2",
"max_gram": "20"
}
},
"ngram_analyzer": {
"filter": [
"lowercase",
"nGram"
],
"type": "custom",
"tokenizer": "standard"
}
}
}
}
}
}
NB: ngram_analyzer is just a name. You can call it whatever.
min_gram & max_gram: Pick numbers that work for you.
Learn more about n-gram filter, the goods and bad here: N-GRAM
Then you can add the analyzer to your field mapping like,
{
"title": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256,
"analyzer": "ngram_analyzer"
}
}
}
}
Lastly for exact matches, these work on type keyword. So based on your mapping, you already have the keyword field so you can use term query to get the exact match by searching on the title.keyword field;
GET {index-name}/{mapping}/_search
{
"query": {
"term": {
"title.keyword": {
"value": "sync accounts data test"
}
}
}
}
Also, you will want to read/ learn more about these solutions and decide on the best solution based on your indexing setup and needs. Also, there may be more ways to achieve what you need, this should be a good start.
I am working on an express js application where I need to update a nested array.
1) Schema :
//Creating a mongoose schema
var userSchema = mongoose.Schema({
_id: {type: String, required:true},
name: String,
sensors: [{
sensor_name: {type: String, required:true},
measurements: [{time: String}]
}] });
2)
Here is the code snippet and explanation is below:
router.route('/sensors_update/:_id/:sensor_name/')
.post(function (req, res) {
User.findOneAndUpdate({_id:req.body._id}, {$push: {"sensors" :
{"sensor_name" : req.body.sensor_name , "measurements.0.time": req.body.time } } },
{new:true},function(err, newSensor) {
if (err)
res.send(err);
res.send(newSensor)
}); });
I am able to successfully update a value to the measurements array using the findOneAndUpdate with push technique but I'm failing when I try to add multiple measurements to the sensors array.
Here is current json I get if I get when I post a second measurement to the sensors array :
{
"_id": "Manasa",
"name": "Manasa Sub",
"__v": 0,
"sensors": [
{
"sensor_name": "ras",
"_id": "57da0a4bf3884d1fb2234c74",
"measurements": [
{
"time": "8:00"
}
]
},
{
"sensor_name": "ras",
"_id": "57da0a68f3884d1fb2234c75",
"measurements": [
{
"time": "9:00"
}
]
}]}
But the right format I want is posting multiple measurements with the sensors array like this :
Right JSON format would be :
{
"_id" : "Manasa",
"name" : "Manasa Sub",
"sensors" : [
{
"sensor_name" : "ras",
"_id" : ObjectId("57da0a4bf3884d1fb2234c74"),
"measurements" : [
{
"time" : "8:00"
}
],
"measurements" : [
{
"time" : "9:00"
}
]
}],
"__v" : 0 }
Please suggest some ideas regarding this. Thanks in advance.
You might want to rethink your data model. As it is currently, you cannot accomplish what you want. The sensors field refers to an array. In the ideal document format that you have provided, you have a single object inside that array. Then inside that object, you have two fields with the exact same key. In a JSON object, or mongo document in this context, you can't have duplicate keys within the same object.
It's not clear exactly what you're looking for here, but perhaps it would be best to go for something like this:
{
"_id" : "Manasa",
"name" : "Manasa Sub",
"sensors" : [
{
"sensor_name" : "ras",
"_id" : ObjectId("57da0a4bf3884d1fb2234c74"),
"measurements" : [
{
"time" : "8:00"
},
{
"time" : "9:00"
}
]
},
{
// next sensor in the sensors array with similar format
"_id": "",
"name": "",
"measurements": []
}],
}
If this is what you want, then you can try this:
User.findOneAndUpdate(
{ _id:req.body._id "sensors.sensor_name": req.body.sensor_name },
{ $push: { "sensors.0.measurements": { "time": req.body.time } } }
);
And as a side note, if you're only ever going to store a single string in each object in the measurements array, you might want to just store the actual values instead of the whole object { time: "value" }. You might find the data easier to handle this way.
Instead of hardcoding the index of the array it is possible to use identifier and positional operator $.
Example:
User.findOneAndUpdate(
{ _id: "Manasa" },
{ $push: { "sensors.$[outer].measurements": { "time": req.body.time } } }
{ "arrayFilters:" [{"outer._id": ObjectId("57da0a4bf3884d1fb2234c74")}]
);
You may notice than instead of getting a first element of the array I specified which element of the sensors array I would like to update by providing its ObjectId.
Note that arrayFilters are passed as the third argument to the update query as an option.
You could now make "outer._id" dynamic by passing the ObjectId of the sensor like so: {"outer._id": req.body.sensorId}
In general, with the use of identifier, you can get to even deeper nested array elements by following the same procedure and adding more filters.
If there was a third level nesting you could then do something like:
User.findOneAndUpdate(
{ _id: "Manasa" },
{ $push: { "sensors.$[outer].measurements.$[inner].example": { "time": req.body.time } } }
{ "arrayFilters:" [{"outer._id": ObjectId("57da0a4bf3884d1fb2234c74"), {"inner._id": ObjectId("57da0a4bf3884d1fb2234c74"}}]
);
You can find more details here in the answer written by Neil Lunn.
refer ::: positional-all
--- conditions :: { other_conditions, 'array1.array2.field_to_be_checked': 'value' }
--- updateData ::: { $push : { 'array1.$[].array2.$[].array3' : 'value_to_be_pushed' } }
I am looking out methods of Extracting only portion of JSON document with REST API search call in MarkLogic using JavaScript or XQuery.
I have tried using query options of re extract-document-data but was not successful. Tried checking my extract path using CTS.validextract path but that function was not recognised in Marklogic 9.0-1
Do I have to using specific search options like constraints or structured query.
Could you please help out? TIA.
I have below such sample document
{
"GenreType": {
"Name": "GenreType",
"LongName": "Genre Complex",
"AttributeDataType": "String",
"GenreType Instance Record": [
{
"Name": "GenreType Instance Record",
"Action": "NoChange",
"TitleGenre": [
"Test1"
],
"GenreL": [
"Test1"
],
"GenreSource": [
"ABC"
],
"GenreT": [
"Test1"
]
},
{
"Name": "GenreType Instance Record",
"Action": "NoChange",
"TitleGenre": [
"Test2"
],
"GenreL": [
"Test2"
],
"GenreSource": [
"PQR"
],
"GenreT": [
"Test2"
]
}
]
}
}
in which i need to search a document with attribute "TitleGenre" WHERE GenreSource = “ABC” in the GenreType complex attribute. It's an array in json document.
I was using the search option as below, (writing search option in XML, but searching the in json documents)
<extract-path>/GenreType/"GenreType Instance Record"[#GenreSource="ABC"]</extract-path>
I am still facing the issues. If possible could you please let me know how json documents can be searched for such specific requirement? #Wagner Michael
You can extract document data by using the extract-document-data option.
xquery version "1.0-ml";
let $doc := object-node {
"GenreType": object-node {
"Name": "GenreType",
"LongName": "Genre Complex",
"AttributeDataType": "String",
"GenreType-Instance-Record": array-node {
object-node {
"TitleGenre": array-node {
"Test1"
},
"GenreSource": array-node {
"ABC"
}
},
object-node {
"TitleGenre": array-node {
"Test2"
},
"GenreSource": array-node {
"PQR"
}
}}
}
}
return xdmp:document-insert("test.xml", $doc);
import module namespace search = "http://marklogic.com/appservices/search"
at "/MarkLogic/appservices/search/search.xqy";
search:search(
"Genre Complex",
<options xmlns="http://marklogic.com/appservices/search">
<extract-document-data>
<extract-path>/GenreType/GenreType-Instance-Record[GenreSource = "ABC"]</extract-path>
</extract-document-data>
</options>
)
In this case /GenreType/GenreType-Instance-Record is the xpath to the extracted element.
Relating to your comment, i also added a predicate [GenreSource = "ABC"]. This way only GenreType-Instance-Record which have a GenreSource of "ABC" are being extracted!
Result:
....
<search:extracted kind="array">[{"GenreType-Instance-Record":{"TitleGenre":["Test1"], "GenreSource":["ABC"]}}]
</search:extracted>
....
Note:
You can add multiple <search:extract-path> elements!
I had to change the name of GenreType Instance Record to GenreType-Instance-Record. I am not sure if you can have property names with whitespaces and access them with xpath. I couldn't get it working this way.
Please post your search options, if this does not work for you.
Edit: Added a predicate to the extract-path.
Thank you so much Wagner, for your prompt trials. Helped me look out for accurate solution to my problem as of now. I have used below extract path, as i could not modify the names in documents. /GenreType/array-node("GenreType Instance Record")/object-node()/TitleGenre[following-sibling::GenreSource="ABC"]
New to angular, and it is awesome.
One thing I am having a brain fart on is parsing a JSON feed that contains namespaces:
Example from JSON feed:
"title": {
"label": "Fuse"
},
"im:name": {
"label": "John Doe"
},
"im:image": [ {
"label": "70x70",
"attributes": {
"height": "55"
}
}, {
"label": "80x80",
"attributes": {
"height": "60",
"im:link": "www.google.com"
}
}, {
"label": "90x90",
"attributes": {
"height": "170"m
"im:link": "www.yahoo.com"
}
}],
I can successfully parse items without namespaces fine like so:
<p ng-repeat="item in results.feed['entry']">
title: {{item.title['label']}}
</p>
But cannot get the items with namespaces to display using:
name: {{item.['im:name']['label']}}
OR
name: {{item.['im-name']['label']}}
OR
name: {{item.['im->name']['label']}}
Since being a newbie, I thought something like this would work:
<div xmlns:im="http://www.aol.com" id="im-app" im-app="im">
<p ng-repeat="item in results.feed['entry']">
…namespace code in here…
</p>
</div>
But that did not help.
Extra bonus question: What if a namespace contains attributes, that also contain namespaces?
Any help would greatly be appreciated.
Thanks!
Roc.
Although Craig answered the question,
This is also for reference for others:
If you want to target a specific key inside of an object set:
"im:image":[
{
"label":google",
"attributes":{
"height":"55"
}
},
{
"label":"yahoo",
"attributes":{
"height":"60"
}
},
{
"label":"aol",
"attributes":{
"height":"170"
}
}
{{item['im:image'][2]['label']}}
Will get the 3rd key in that set.
Thanks.
Get rid of the dot after item
Working example: http://jsfiddle.net/bonza_labs/Kc2uk/
You access the properties exactly the same way as straight javascript (because angular is basically eval()-ing the expression as javascript**). item.['foo'] is not valid javascript. You are correct in using square-bracket notation as my:name is not valid for dot-notation.
valid:
item.foo
item['foo']
with non-standard property names:
item['foo:bar']
item['foo-bar']
and in your case:
{{item['im:name']['label']}}
** or close enough for understanding this solution
I have a JSON object which returns following values.
{
"articles":[
{
"paper-id":"id",
"paper-id-type":"type",
"title":"title",
"url":"url",
"abstract":"abs",
"date":"date",
"publication-forum":"forum",
"publication-forum-type":"type",
"authors":"auth",
"keywords":"key1,key2"
}
}
I tried to access these results through JavaScript.
First I created an array and assigned these results to the array.
The content of the array (named articles) object looks like this;
abstract: "xxx"
authors: "yyy"
date: "1111"
keywords: "key1, key2"
paper-id: "abc"
paper-id-type: "xxx"
publication-forum: "yyy"
publication-forum-type: "zzz"
title: "www"
url: "url"
Then I tried to access each value in these elements using the format,
articles[0]["abstract"]
It works for elements that do not have "-" character. So when I tried to extract the paper-id;
articles[0]["paper-id"]
I'm getting the error [Exception: SyntaxError: Unexpected token []
Does anyone know how to solve this problem ?
The problem is because you forgot to close the [] and the {} in your JSON
You JSON should look like this
{
"articles":[
{
"paper-id":"id",
"paper-id-type":"type",
"title":"title",
"url":"url",
"abstract":"abs",
"date":"date",
"publication-forum":"forum",
"publication-forum-type":"type",
"authors":"auth",
"keywords":"key1,key2"
}]
}
abc = {
"articles": [{
"paper-id": "id",
"paper-id-type": "type",
"title": "title",
"url": "url",
"abstract": "abs",
"date": "date",
"publication-forum": "forum",
"publication-forum-type": "type",
"authors": "auth",
"keywords": "key1,key2"
}
]
};
for (i in abc['articles'][0]) {
console.log(abc['articles'][0][i]);
}