Mongo query with 'like' (regex); extract the field that provide the matching - mongodb

I'm looking some way for extract the field that provide matching. Example from mongo shell:
db.estates.find({$or: [{street: /a/i}, {number: '64'}]}, {street: 1, number: 1})
{ "_id" : ObjectId("551f8b1efec981df83afbaee"), "number" : "123", "street" : "abcd" }
{ "_id" : ObjectId("551f8b36fec981df83afbb05"), "street" : "qwer", "number" : "64" }
I want to get in results some value pointing to field that provided the matching, or get only this field. Is it real?

Related

MongoDB count occurances of a substring in a collection

Hello I'm a MongoDb beginner. I have a database of a IRC chatlog. The document structure is very simple
{
"_id" : ObjectId("000"),
"user" : "username",
"message" : "foobar foobar potato idontknow",
"time" : NumberLong(1451775601469)
}
I have thousands of these and I want to count the number of occurrences of the string "foobar". I have googled this issue and found something about aggregations. I looks very complicated and I haven't really found any issue this "simple". I'd be glad if someone pointed me in the right direction what to research and I wouldn't mind an example command that does exactly this what I want. Thank you.
There is no any built-in operator to solve your request.
You can try this query, but it has very poor performance:
db.chat.find().forEach(function(doc){
print(doc["user"] + " > " + ((doc["message"].match(/foobar/g) || []).length))
})
If you could change your message field to array, then we could apply aggregation...
EDIT:
If you add array of splitted words into your entry, we can apply aggregation
Sample:
{
"_id" : ObjectId("569bb7040586bcb40f7d2539"),
"user" : "username",
"fullmessage" : "foobar foobar potato idontknow",
"message" : [
"foobar",
"foobar",
"potato",
"idontknow"
],
"time" : NumberLong(1451775601469)
}
Aggregation. We create new entry for each array element, match given word (foobar, in this case) and then count matched result.
db.chat.aggregate([
{"$unwind" : "$message"},
{"$match" : {"message" : {"$regex" : "foobar", "$options" : "i"}}},
{"$group" : {_id:{"_id" : "$_id", "user" : "$user", "time" : "$time", "fullmessage" : "$fullmessage"}, "count" : {$sum:1}}},
{"$project" : {_id:"$_id._id", "user" : "$_id.user", "time" : "$_id.time", "fullmessage" : "$_id.fullmessage", "count" : "$count"}}
])
Result:
[
{
"_id" : ObjectId("569bb7040586bcb40f7d2539"),
"count" : 2,
"user" : "username",
"time" : NumberLong(1451775601469),
"fullmessage" : "foobar foobar potato idontknow"
}
]

MongoDB search error

I use mongoDB (version 3.0.2) for my application and if I will search for a User named "Hannes" than I get the following error above.
db.User.find() works without any problems.
Does anyone know what the problem is?
Thanks a lot!
db.User.find({$text:{$search:'Hannes'}})
Error: error: {
"$err" : "Unable to execute query: error processing query: ns=apoSoftDatabase.User limit=0 skip=0\nTree: TEXT : query=Hannes, language=, tag=NULL\nSort: {}\nProj: {}\n planner returned error: need exactly one text index for $text query",
"code" : 17007
}
[EDIT]
This is my document structure:
db.User.insert({ "_id" : ObjectId("5589929b887dc1fdb501cdbf"), "_class" : "com.smartinnotec.aposoft.dao.domain.User", "title" : "", "firstname" : "Claudia", "surname" : "Amreiter", "birthdate" : ISODate("1989-06-02T03:43:43.124Z"), "sex" : "FEMALE", "telephone" : "0664 / 342233223", "email" : "claudia.amreiter#aon.de", "username" : "claudia", "password" : "claudiapw", "address" : { "_id" : null, "street" : "strasse 21a", "postalCode" : 58441, "region" : "village", "country" : "Germany" }})
The "error" is because uou don't have a "text" index on your collection and you need one to use the $text operator in queries.
Create a text index
Your document may have fields like:
{
"a": "sam",
"b": "wise"
}
You can then create a "text index" over all or just a single field with something like:
db.collection.createIndex({ "a": "text", "b": "text" })
Then you can query with:
db.collection.find({ "$text": { "$search": "sam wise" } })
Or any other valid combination without problem.
I don't know the field name of your collection, however you can try this:
Try db.User.find({[field name]:'Hannes'})

MongoDB update a subdocument attribute

Let me start by saying I'm sorry if this has been answered, but I can't get other questions on this site to fit my needs and, more importantly, work.
I have the below example document, with a subdocument of 'address':
{
"_id" : ObjectId("....")
,"addresses" :
[{
"start" : ISODate("1973-07-10T00:11:51.111Z")
,"value" : "123 long road"
}]
}
What I need to do is to close the existing address record with an end attribute, and add a new line for the new address with a new start and value attribute. Eventually, I'll need to do this again so the code needs to update the subdocument record where end does not exist.
The below code does not work, but it's about as far as I can get:
db.sites.update(
{"_id" : ObjectId("....")
, "addresses.end" : {"$exists" : false}}
,{"$set": {"addresses.$.end" : "fdsa"}});
This gives the error:
Cannot apply the positional operator without a corresponding query field containing an array.
Can anyone point me in the right direction?
Juste replace in your query "addresses.end" : {"$exists" : false} with:
addresses: {$elemMatch: {end: {$exists: false}}}
Your address field is poorly defined. you need make it a subdocument or an array of subdocuments. ie {
"_id" : ObjectId("....")
,"addresses" :
[
{
"start" : ISODate("1973-07-10T00:11:51.111Z")
,"value" : "123 long road"
}
]
}
your query should then work!
I think that the Query should be more specific
**Updated **
db.sites.update ( {"_id" : ObjectId("...."), addresses: { "$elemMatch" : { end:{$exists : false}} } }, {"$set": {"addresses.$.end" : "fdsa"}});
db.sites.find()
results:
{
"_id" : ObjectId("53df93da560b7815e1237934"),
"addresses" : [
{
"start" : ISODate("1973-07-10T00:11:51.111Z"),
"value" : "123 long road",
"end" : "fdsa"
}
]
}
but you can update only one
Take a look http://docs.mongodb.org/manual/reference/operator/projection/positional/#proj.S
You can t update more element in Array https://jira.mongodb.org/browse/SERVER-1243

How to do query on multiple nested data fields in MongoDB

So, what I'm trying to do is query all documents that have a City of 'Paris' and a State of 'France'. I need to do some kind of join, but I haven't been able to figure out how to construct it.
I'm using the c# driver, but I'll gladly accept help using any method.
{
"_id" : ObjectId("519b407f3c22a73a7c29269f"),
"DocumentID" : "1",
"Meta" : [{
"Name" : "City",
"Value" : "Paris",
}, {
"Name" : "State",
"Value" : "France",
}
}]
}
{
"_id" : ObjectId("519b407f3c22a73a7c29269g"),
"DocumentID" : "2",
"Meta" : [{
"Name" : "City",
"Value" : "Paris",
}, {
"Name" : "State",
"Value" : "Texas",
}
}]
}
The $elemMatch operator is used to indicate that all the conditions within it must be matched by the same array element. So (to switch to shell syntax) to match all documents which have meta city Paris you would do
db.collection.find( {Meta:{$elemMatch:{Name:"City",Value:"Paris"}}} )
This assures you won't match something which has Name: "somethingelse", Value: "Paris" somewhere in its array with a different array element matching the Name:"City".
Now, default combination for combining query conditions is "and" so you can continue adding attributes:
db.collection.find( {Meta: {
$elemMatch:{Name:"City",Value:"Paris"},
$elemMatch:{Name:"State",Value:"France"}
}
}
)
Now if you want to add another condition you keep adding it but if you want a NOT then you do it like this:
db.collection.find( {Meta: {
$elemMatch:{Name:"City",Value:"Paris"},
$elemMatch:{Name:"State",Value:"France"},
$not: {$elemMatch:{Name:"Arrondissement",Value:"Louvre"}}
}
}
)
I might be answering my own question here, but I'm new to MongoDB, so while this appears to give me the results I'm after, it might not be the optimum approach.
var result = collection.Find(
Query.And(
Query.ElemMatch("Meta", Query.EQ("Name", "City")),
Query.ElemMatch("Meta", Query.EQ("Value", "Paris")),
Query.ElemMatch("Meta", Query.EQ("Name", "State")),
Query.ElemMatch("Meta", Query.EQ("Value", "France")))
);
Which leads to a follow up - how would I get all of the documents whose 'City' is 'Paris' and 'State' is 'France' but whose 'Arrondissement' is not 'Louvre'?

mongodb replace all instances of certain value for subdocument

My collection (called "workers"):
"_id" : "500"
"type" : "Manager",
"employees" : [{
"name" : "bob"
"id" : 101
},{
"name" : "phil"
"id" : 102
}]
Goal: for every _id that is a type: Manager AND that contains a subdocument that has an "id" of 102: replace 102 with 202.
Desired End result:
"_id" : "500"
"type" : "Manager",
"employees" : [{
"name" : "bob"
"id" : 101
},{
"name" : "phil"
"id" : 202
}]
I have tried:
db.workers.update({type:'Manager','employees.id':'102'},{$set:{'employees.id':'202'}},{multi:true})
I then did the following two things to verify:
db.workers.find({type: "Manager", 'employees.id': 102}).count()
I get a result of 9.
I also tried this to verify:
db.workers.find({$and: [{type: "Manager"},{"employees.id":60}]}).count()
This returned 0.
I am pretty confused at this point. Is my update wrong? is my find wrong? Is it both? Is the '9' result wrong? Is the '0' wrong?
You need to use the $ positional update operator to update the specific element that matched your query. Your update is also using values of '102' and '202' which makes the update try and match strings when those fields are numbers.
Your update should look like this instead:
db.workers.update(
{type: 'Manager', 'employees.id': 102},
{$set: {'employees.$.id': 202}},
{multi: true})