Delete fields from array in mongodb using java driver - mongodb-query

I need delete all fields from the devices array they have the condition where state = 0
And this is my mongodb document:
{ "_id" : { "$oid" : "53e53553b76000127cb1ab80"} ,
"city" : "Some Place" ,
"devices" :
[ { "guid" : "local" , "brand" : "SSSS" , "state" : 1} ,
{ "guid" : "local2" , "brand" : "DDD" , "state" : 0} ,
{ "guid" : "local2" , "brand" : "DDD" , "state" : 0} ,
{ "guid" : "local2" , "brand" : "DDD" , "state" : 0}] ,
"phone": 8888888888,
"sex" : "Male"
}
This is my java code that I'm trying:
DBCollection collection = db.getCollection(usersCollection);
BasicDBObject query2 = new BasicDBObject("_id", id);
((BasicDBObject) query2).append("devices.guid", device);
((BasicDBObject) query2).append("devices.state", 0);
collection.remove(query2);
But this query delete all devices from the document.
Thanks in advance!

You need to do the equivalent of:
db.usersCollection.update(
{"_id":"yourId"},
{$pull:
{ "devices" :
{ $elemMatch :
{
"guid":"local2",
"state":"0"
}
}
}
}
)
Where you replace the yourId with the ID you want to query
That is, instead of using remove, use update, with $pull in the BasicDBObject. I can't test this right now but try:
DBCollection collection = db.getCollection(usersCollection);
BasicDBObject query = new BasicDBObject("_id", id);
BasicDBObject deviceToDelete = new BasicDBObject("guid",device);
deviceToDelete.append("state", "0");
BasicDBObject obj = new BasicDBObject("devices", deviceToDelete);
collection.update(query, new BasicDBObject("$pull",obj));
Let me know if this works (again I can't test because I don't have mongod on my machine).

I fix the problem following this answer
This code works:
DBCollection collection = db.getCollection(usersCollection);
BasicDBObject match = new BasicDBObject("_id", id);
BasicDBObject update2 = new BasicDBObject("devices", new BasicDBObject("guid", device)
.append("state", 0));
collection.update(match, new BasicDBObject("$pull", update2));

You cannot use the remove-Function to remove a embeded document, you need to use update instead. This is the function call you need to implement in java:
db.userCollection.update(
{_id: ObjectId("53e53553b76000127cb1ab80")},
{$pull:
{ devices :
{state: 0}
}
})
Notice that the update-function takes to arguments, the first one to find the document and the second one to modify it.
DBCollection collection = db.getCollection(usersCollection);
BasicDBObject query = new BasicDBObject("_id", newObjectID("53e53553b76000127cb1ab80"));
BasicDBObject condition = new BasicDBObject("state",0);
BasicDBObject array = new BasicDBObject("devices", condition);
BasicDBObject update = new BasicDBObject("$pull", array);
collection.update(query, update);
I didn't test the Java Code but I tested the function call in mongoDB.
If it doesn't work, check the implementation first.

Related

PostgreSQL - Update inner json

I have a column jdata of type jsonb inside a table 'JTABLE'. A sample jdata looks like this :
{
"id" : 12,
"address" : {
"houseName": {
"name" : "Jackson",
"lang" : "ENG"
}
}
}
How can i query to update the lang to anotherValue for this?
I tried this and it doesn't seem to work :
UPDATE JTABLE SET jdata -> 'address'->'houseName'-> 'lang' = '"DEU"' where jdata->>'id' = '12';
This doesn't work! Any help?
EDIT:
This overwrites my value and i get this when i run :
{
"id" : 12,
"address" : {
"houseName": {
"lang" : "DEU"
}
}
}
I lost key name.
I'm trying this query now :
SELECT jsonb_set(jdata, 'address,houseName}', '{"lang":"DEU"}'::jsonb) FROM JTABLE where jdata->>'id' = '12';
Your path is wrong, the 2nd statement should be a path to the json key you wish to update.
The query to view your update should look like :
SELECT jsonb_set(jdata, '{address,houseName,lang}', '"DEU"') FROM JTABLE where jdata->'id' = '12';
The final query to update :
UPDATE JTABLE SET jdata = jsonb_set(jdata, '{address,houseName,lang}', '"DEU"') WHERE jdata->'id' = '12';
Also don't type cast a record to `jsonb.

Elm record shorthand notation

To get better at functional programming in JavaScript, I started leaning Elm.
In JavaScript you have the object shorthand notation:
const foo = 'bar';
const baz = { foo }; // { foo: 'bar' };
I was wondering whether there is something like that in Elm? I'm asking because I have the following model:
type alias Model =
{ title : String
, description : String
, tag : String
, tags : List String
, notes : List Note
}
type alias Note =
{ title : String
, description : String
, tags : List String
}
And an update function that upon receiving the AddNote action adds the note to the notes array and clears the inputs:
AddNote ->
{ model | notes = model.notes ++ [ { title = model.title, description = model.description, tags = model.tags } ], title = "", description = "", tag = "" }
I know that in function definitions you can "destructure" records, but I think even in the return type I would have to explicitly type out each key of the record.
AddNote ->
{ model | notes = model.notes ++ [ getNote model ], title = "", description = "", tag = "" }
getNote : Model -> Note
getNote { title, description, tags } =
{ title = title, description = description, tags = tags }
There is not a shorthand record notation similar to JavaScript objects.
However, a type alias also serves as a constructor function, so you could have something like this:
getNote : Model -> Note
getNote { title, description, tags } =
Note title description tags

Querying ravendb index using named field and collection

I have the following index in ravendb, Changes_Which is a named field and this maps to a sub collection
public My_Index()
{
Map = revisions => from revision in revisions
from change in revision.Changes
where (revision.AuditedType == "typeA")
select
new
{
revision.ChangeTimestamp,
Changes_Which = change.Which
};
}
the json for a revision looks like:
{
"AuditedType" : "typeA",
"Changes": [
{
"SubWhich": null,
"Which": "Regulation",
"Original": "Unknown",
"New": "Yes"
},
{
"SubWhich": null,
"Which": "Other",
"Original": "Unknown",
"New": "Yes"
},
{
"SubWhich": null,
"Which": "Regulation",
"Original": "Unknown",
"New": "Yes"
}
]
"ChangeTimestamp": "2011-05-03"
}
I am trying to filter the results from the index using the Changes_Which field:
var q = session.Advanced.LuceneQuery<revision>("My_Index/Index")
.WaitForNonStaleResultsAsOfLastWrite()
.AddOrder(paging.SortColumn, paging.SortOrder == "desc")
.Skip(((paging.CurrentPage - 1) * paging.RecordsPerPage))
.Take(paging.RecordsPerPage);
if (fromDate > DateTime.MinValue && toDate > DateTime.MinValue)
{
q = q.WhereGreaterThanOrEqual("ChangeTimestamp", fromDate)
.AndAlso()
.WhereLessThanOrEqual("ChangeTimestamp", toDate.AddDays(1).AddMinutes(-1));
}
if (removeNoChange)
{
q = q.AndAlso().Not.WhereEquals("Changes_Which", "Regulation");
}
This line:
q = q.AndAlso().Not.WhereEquals("Changes_Which", "Regulation");
does work, but only removes the first match on "Which": "Regulation", the third one in the collection remains.
Any suggestions appreciated.
The reason for this is that you are outputting different index entries for the same document.
When searching in RavenDB, you are searching on documents, and in your case, you filtered out the first index entry on that document, but there are other index entries that match, so it is returned.
You are probably better off with:
Map = revisions => from revision in revisions
where (revision.AuditedType == "typeA")
select
new
{
revision.ChangeTimestamp,
Changes_Which = revision.Changes.Select(chnage => change.Which)
};
This will output just a single entry per document (which is recommended) and will result in filtering of all documents that were changed because of Regulation

Index analyzer not working with Elasticsearch.net And Nest

my code is it.. using nest, elasticsearch 2.3.0 Version
i want mapping( + custom analyzer) & create index ...
but mapping is not unsuccessful low level call error!
please , check my code and review for me
var node = new Uri("http://localhost:9200");
var settings = new ConnectionSettings(node);
var client = new ElasticClient(settings);
var request = new IndexExistsRequest("aa");
var result = client.IndexExists(request);
if (result.Exists == true)
{
client.DeleteIndex("aa", null);
}
var ilhee_Custom = new CustomAnalyzer
{
Filter = new List<string> { "lowercase", "stop", "standard", "snowball" },
Tokenizer = "standard"
};
List<Person> categList = new List<Person>();
var Person = new Person
{
id = 1,
Firstname = "an apples bananas boxes, the sun.",
Lastname = "a beautiful womens with a good guys in there"
};
categList.Add(Person);
var response = client.CreateIndex("aa");
var mappingResponse = client.Map<Person>(d => d
.Properties(props => props
.String(s => s
.Name(p => p.Firstname)
.Index(FieldIndexOption.Analyzed)
.Analyzer("ilhee_Custom")
)
.String(s1 => s1
.Name(p1 => p1.Lastname)
.NotAnalyzed()
)
)
.Index("aa")
.Type("person")
);
var b = client.IndexMany<Person>(categList, "aa", "person");
You create a custom analyzer but you don't send it to Elasticsearch, so when it comes to using it in a mapping, Elasticsearch knows nothing about the custom analyzer.
You can create a new index with analysis and mappings in one request. Here's an example of creating an index, adding your custom analyzer and mapping as part of the index creation
void Main()
{
var node = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var settings = new ConnectionSettings(node)
// set "aa" as the default index; if no index
// is specified for a type or in the request,
// the default index will be used
.DefaultIndex("aa");
var client = new ElasticClient(settings);
var indexExistsResponse = client.IndexExists("aa");
if (indexExistsResponse.Exists)
{
client.DeleteIndex("aa", null);
}
var people = new List<Person>{
new Person
{
id = 1,
Firstname = "an apples bananas boxes, the sun.",
Lastname = "a beautiful womens with a good guys in there"
}
};
var createIndexResponse = client.CreateIndex("aa", c => c
.Settings(s => s
.Analysis(a => a
.Analyzers(ad => ad
// give the custom analyzer a name
.Custom("ilhee_Custom", ca => ca
.Tokenizer("standard")
.Filters("lowercase", "stop", "standard", "snowball")
)
)
)
)
.Mappings(m => m
.Map<Person>(d => d
.Properties(props => props
.String(s => s
.Name(p => p.Firstname)
.Analyzer("ilhee_Custom")
)
.String(s1 => s1
.Name(p1 => p1.Lastname)
.NotAnalyzed()
)
)
)
)
);
var indexManyResponse = client.IndexMany<Person>(people, "aa");
// refresh the index after indexing, so that newly indexed documents
// are available in search results.
client.Refresh("aa");
var searchResponse = client.Search<Person>(s => s
.Query(q => q
.Match(m => m
.Field(p => p.Firstname)
.Query("boxes")
)
)
);
}
public class Person
{
public int id { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set;}
}
The search returns back our indexed document as expected
{
"took" : 9,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 0.15342641,
"hits" : [ {
"_index" : "aa",
"_type" : "person",
"_id" : "1",
"_score" : 0.15342641,
"_source" : {
"id" : 1,
"firstname" : "an apples bananas boxes, the sun.",
"lastname" : "a beautiful womens with a good guys in there"
}
} ]
}
}

Dijit validator question within dynamically created validationbox , please help

I'm now trying to do a dynamically created table line , with dijit button, validation box.
The button id and textbox id is generate by index number, so how can my Validation box validator can know which line of validationbox is calling the validator?
Should I make the validator : testcall , being validator : function () {testcall(this.id)}, ????
function createNewRow() {
var tablebodyname = "RPDetailbody" ;
var mytablebody = document.getElementById(tablebodyname);
var thetabletr = document.createElement('tr');
var thetabletd1 = document.createElement('td');
var thetabletd2 = document.createElement('td');
var thetabletd3 = document.createElement('td');
var thisButton = new dijit.form.Button({
label : thelineindex ,
id : "I_del_butt"+thelineindex,
name : "I_del_butt"+thelineindex,
onClick : function() {
document.getElementById(tablebodyname).removeChild(thetabletr);
}
}).placeAt( thetabletd1 ) ;
var thisNumberTextBox = new dijit.form.NumberTextBox({
id : "I_seq_no"+thelineindex ,
name : "I_seq_no"+thelineindex ,
value : thelineindex+1 ,
required : "true",
maxLength : 2,
size : 2 ,
style : "width: 2em;",
missingMessage : "Every line must have sequence number"}).placeAt(thetabletd2) ;
var thisValidationTextBox1 = new dijit.form.ValidationTextBox({
id : "I_pig_code"+thelineindex ,
name : "I_pig_code"+thelineindex ,
type : "text" ,
required : "true",
maxLength : 3,
size : 3,
style : "width: 5em;",
validator : testcall ,
missingMessage : "Must have pigment code" }).placeAt(thetabletd3) ;
thetabletr.appendChild(thetabletd1);
thetabletr.appendChild(thetabletd2);
thetabletr.appendChild(thetabletd3);
mytablebody.appendChild(thetabletr);
thelineindex ++ ;
}
<tbody id="RPDetailbody">
<td><div id="delplace"></div></td>
<td><div id="seqplace"></div></td>
<td><div id="pigcodeplace"></div></td>
</tr>
</tbody>
However I've try to make it as javascript function call to my validator , but I found in the form submittion , using form.isValid() to verify all information can pass validation, it always returns fail !
Here are my validator :
function testcall ( thebtnID ) {
var strlen = thebtnID.length ;
var resultAreaID = "I_pigment_name"+ thebtnID.substring(10, strlen) ;
var pigcode = dijit.byId(thebtnID );
var bNoNameFound = ( "Error" == pigcode.get( "state" ) ) ? false:true;
var query = "thePig=" + encodeURI(pigcode.value );
if( "" == pigcode.value ) {
// for some required=true is not kicking in, so we are forcing it.
bNoNameFound = false;
pigcode._setStateClass();
} else {
if( false == pigcode._focused ) {
console.log( "Checking Pigment..." );
dojo.xhrPost({
url: 'ValidatePigmentInput.php',
handleAs: 'text',
postData: query ,
load: function( responseText ) {
if ( responseText == "no record!" ) {
// setting the state to error since the pigment is already taken
bNoNameFound = false;
pigcode.set( "state", "Error" );
//pigcode.displayMessage( "The Pigment dosen't exist..." );
document.getElementById(resultAreaID).innerHTML = "The Pigment dosen't exist...";
// used to change the style of the control to represent a error
pigcode._setStateClass();
} else {
if ( responseText == "pigment BANNED!" ) {
bNoNameFound = false;
pigcode.set( "state", "Error" );
document.getElementById(resultAreaID).innerHTML = "Pigment BANNED! Please don't use it!";
pigcode._setStateClass();
} else {
bNoNameFound = true;
pigcode.set( "state", "" );
document.getElementById(resultAreaID).innerHTML = responseText;
pigcode._setStateClass();
}
}
},
error: function(responseText) {
document.getElementById(resultAreaID).innerHTML = "Error";
}
});
}
}
return bNoNameFound;
}
You can do:
var thisValidationTextBox1 = new dijit.form.ValidationTextBox({
id: "I_pig_code" + thelineindex,
name: "I_pig_code" + thelineindex,
type: "text",
required: "true",
maxLength: 3,
size: 3,
style: "width: 5em;",
missingMessage: "Must have pigment code"
}).placeAt(thetabletd3);
thisValidationTextBox1.validator = function() {
return testcall(thisValidationTextBox1.id);
};
Ie. you need to pass the id to your testcall() function, but also you need to explicitly override the validator property of the widget.
See this in the Dojo reference guide.