I am new to Morphia and am trying to update a field in embedded document. This is the current structure
class A {
List<B> BList;
}
class B {
String field;
}
So My structure looks like the following in MongoDb :
{
"_id" : ObjectId("5bab8be0032945f6e9f91d98"),
"className" : "com.abc.A",
"BList" : [
{
"B" : {
"field" : "text"
}
}
}
Now I want to update B.field for all the matching queries.
I created the following UpdateOperations
UpdateOperations updateOps = datastore.createUpdateOperations(A.class);
my filter query was fine say filter returning me all elements in A.
updateOps.set("Blist.$[].B.field", "newtext");
when debugger reached this statement it shows org.mongodb.morphia.query.ValidationException: Could not resolve path 'BList.$[].B.field' against A`
I even added disableValidation But this doesnot run.
However if I ommit the positional operator it works fine but when on runnig datastore.update() it fails.
throwing this error.
Write failed with error code 28 and error message 'Cannot create field B.
Can Anyone suggest how to do this updation on second level in morphia ?
I've a document which has another nested document in it represent a changes (logging). Each change document has a timestamp, field, old and new values. Basically as you can see this document would grow a lot, and I really don't want to get all changes but only a recent one.
What I want to do is make a query and get only those changes which falls in between two time stamps. I am not interested in any other information in document, so I dont want to pull it, just recent changes.
{
.......
"adwordsChanges":[
{
"timestamp":NumberLong("1400162491325"),
"field":"syncState",
"old":null,
"new":"OK"
},
{
"timestamp":NumberLong("1400162491325"),
"field":"keywordId",
"old":null,
"new":NumberLong("23918779329")
},
{
"timestamp":NumberLong("1400162491325"),
"field":"adGroupId",
"old":null,
"new":NumberLong("16972286472")
}
]
}
This is what I've tried!
db.keywords.find(
{
$and :[{"_id" : ObjectId("5374c7a7ac58b0d3b5e970fa")}, {"adwordsChanges.field" : "keywordId"}, {"adwordsChanges.timestamp" : {$gte:NumberLong("11111111"), $lte:NumberLong(99999999999999) }}]
})
Running Andrei's query I am getting compilation error:
assert: command failed: {
"errmsg" : "exception: The top-level _id field is the only field currently supported for exclusion",
"code" : 16406,
"ok" : 0
} : aggregate failed
Error: command failed: {
"errmsg" : "exception: The top-level _id field is the only field currently supported for exclusion",
"code" : 16406,
"ok" : 0
} : aggregate failed
at Error (<anonymous>)
at doassert (src/mongo/shell/assert.js:11:14)
at Function.assert.commandWorked (src/mongo/shell/assert.js:244:5)
at DBCollection.aggregate (src/mongo/shell/collection.js:1149:12)
at (shell):1:13
2014-05-27T15:23:54.945+0100 Error: command failed: {
"errmsg" : "exception: The top-level _id field is the only field currently supported for exclusion",
"code" : 16406,
"ok" : 0
Thanks for any help!
You could use aggregation framework to filter subdocuments, like this:
db.keywords.aggregate({$unwind:"$adwordsChanges"},
{$match:{"adwordsChanges.timestamp" :
{$gte:1400162491325, $lte:23918779329},
"adwordsChanges.field" : "keywordId"}},
{$project:{_id:0,
timestamp:"$adwordsChanges.timestamp",
field:"$adwordsChanges.field",
old:"$adwordsChanges.old",
new:"$adwordsChanges.new"
}});
Explanation of difference between project and group
Initially I thought original document should be returned and group was used to restore original document structure, i.e in this case groupis opposite operation to unwind. After clarification it became clear that only subdocuments were needed, then I replaced group operation with project, so that subdocuments were projected to root level.
Say I insert a document into mongo like below:
db.test.insert({1 : { 2 : "some value"}, 3 : { 4 :"some other value"}});
How do I use the $where clause to match this document? I tried using the following:
db.test.find({"$where" : "this.1.2 == this.3.4"});
but I ended up getting this error message.
error: {
"$err" : "JavaScript execution failed: SyntaxError: Unexpected number",
"code" : 16722
}
I know $where is not recommended, but say if I have to use it, is there any way to accomplish this? Thanks in advance.
It seems that i can go further than one subdocument if i want to add it dynamicaly, here is the code:
db.users.update({"pup.cmn.id":id}, {"$addToSet":{"pup.cmn":{"abus":email}}})
this give error:
OperationFailure: can't append to array using string field name: cmn
then, if i add positional element i get this:
db.users.update({"pup.cmn.id":id}, {"$addToSet":{"pup.$.cmn":{"abus":email}}})
"cmn" :
[
{
"fto" : ObjectId("5190e8a53a5f3a0c102af045")
"id" : "14.05.2013 12:29:53"
},
{
"abus" : "u...#example.com"
}
]
so as you can see, it will add it in the same level, and i dont want that, because the application will get errors.
It seems that Mongodb for the time of writing (2.4.x) have not this feature, there is a ticket:
https://jira.mongodb.org/browse/SERVER-831
I am able to $push an object onto a Mongo array as follows:
db.foo.update({},{$push:{bar:3}})
But I can't find a syntax that will allow me to $pop the last item from the list.
I've tried things like:
db.foo.find({$pop:{bar:1}})
which does nothing. I've also tried
db.foo.find({id:23},{$pop:{bar:1}})
which outputs:
error: { "$err" : "Unsupported projection option: bar", "code" : 13097 }
Any ideas?
$pop exists and works almost like you've got it there, but you need to find some elements first!
db.foo.update({ _id: someId }, { $pop: { bar:1 } });
See the docs.