find records by an array key in a document - mongodb

I have some records like this
{
"_id": "test1",
"friend": {
"test2": {
"name": "ax",
"level": 1,
"intimacy": 0,
"status": 0
},
"test3": {
"name": "es",
"level": 1,
"intimacy": 0,
"status": 0
}
}
},
{
"_id": "test2",
"friend": {
"test2": {
"name": "ff",
"level": 1,
"intimacy": 0,
"status": 0
},
"test3": {
"name": "dd",
"level": 1,
"intimacy": 0,
"status": 0
}
}
}
i need find the node of friend.test2 in the document of _id=test1
i don`t want change the data struct to solve this problem.anyone can help me.
the result maybe like this
{
"test2": {
"name": "ax",
"level": 1,
"intimacy": 0,
"status": 0
}
}

Try below query.
db.<coll>.find({ _id:"test1" }, { "friend.test2":1 })

In mongo shell you can do this:
db.collection.find({_id:"test1"},{"friend.test2":1})
and for php you may try something like
$collection->find(array("_id"=>"test1"),array("friend.test2"=>true))

Following code is working correctly. Tested.
$results = $coll->find(array(), array("_id"=>"test1"),array("friend.test2"=> 1));
foreach($results as $test) {
print_r($test);
}

Related

Query nested object in mongodb without key

I have multiple documents saved which look like the one shown below, how would I query against a nested object without the ID to receive the right document?
Here is what I current, but this doesnt work, as I dont have the ID at the start.
db.collection.find({
"details.hardware.id": 5,
})
This is what ive tested and know works but I dont know the ID -
db.collection.find({
"100201.details.hardware.id": 5,
})
Document example -
[
{
"_id": {
"$oid": "6338b69062433c04642d26ca"
},
"100201": {
"broken": true,
"details": {
"build": {
"id": 1018458,
},
"hardware": {
"id": 5,
"model": {
"id": 131,
},
},
"id": 2811302,
"view": {
"id": 781,
}
},
"id": "100201",
"links": [
{
"details": {
"id": 7832,
},
"id": 15012,
},
{
"description": null,
"details": {
"id": 6528,
"model": {
"id": 530
}
},
"id": 15076,
}
],
"ref": false,
}
}
]
any help would be appreciated

MongoDB - Way to find closest results from arrays inside every document

I want to find closest result from array inside document for every doc, and project it new object using MongoDB. It will be easier to explain what I trying to do by example:
Doc schema:
{
"id": "string",
"name": "string",
"track" : [
{
"time": "number",
"distance": "number"
}
]
}
EXAMPLE:
I want to find closest results for every doc for time equals 4
Input data:
[
{
"id": "1",
"name": "test1",
"track" : [
{
"time": 0,
"distance": 0
},
{
"time": 1,
"distance": 5
},
{
"time": 3,
"distance": 17
},
{
"time": 4,
"distance": 23
},
{
"time": 6,
"distance": 33
}
]
},
{
"id": "2",
"name": "test2",
"track" : [
{
"time": 0,
"distance": 0
},
{
"time": 1,
"distance": 5
},
{
"time": 2,
"distance": 12
},
{
"time": 4,
"distance": 26
},
{
"time": 6,
"distance": 32
}
]
},
{
"id": "3",
"name": "test3",
"track" : [
{
"time": 0,
"distance": 0
},
{
"time": 1,
"distance": 5
},
{
"time": 3,
"distance": 12
}
]
}
]
Output data:
[
{
"id": "1",
"result" : {
"time": 4,
"distance": 23
}
},
{
"id": "2",
"result" : {
"time": 4,
"distance": 26
}
},
{
"id": "3",
"result" : {
"time": 3,
"distance": 12
}
}
]
Is it possible to do this using MongoDB?
db.collection.aggregate([
{
"$addFields": {
"tracks": {
"$filter": {
"input": "$track",
"as": "track",
"cond": {
"$lte": [
"$$track.time",
4
]
}
}
}
}
},
{
"$addFields": {
"tracks": {
"$slice": [
"$tracks",
-1
]
}
}
},
{
"$unwind": "$tracks"
},
{
"$project": {
"tracks": 1,
"name": 1
}
}
])
Play
It does below things:
Finds whose track time is <=4 and adds it to an array called items
Then it gets the last element - i.e closer element
Take the element from array - unwind
Projects what is needed.

MongoDB Aggregation Error Returning wrong result

I have my json object like this
{
"_id": "5c2e811154855c0012308f00",
"__pclass": "QXRzXFByb2plY3RcTW9kZWxcUHJvamVjdA==",
"id": 44328,
"name": "Test project via postman2//2",
"address": "some random address",
"area": null,
"bidDate": null,
"building": {
"name": "Health Care Facilities",
"type": "Dental Clinic"
},
"collaborators": [],
"createdBy": {
"user": {
"id": 7662036,
"name": "Someone Here"
},
"firm": {
"id": 2520967,
"type": "ATS"
}
},
"createdDate": "2019-01-03T21:39:29Z",
"customers": [],
"doneBy": null,
"file": null,
"firm": {
"id": 1,
"name": "MyFirm"
},
"leadSource": {
"name": "dontknow",
"number": "93794497"
},
"location": {
"id": null,
"city": {
"id": 567,
"name": "Bahamas"
},
"country": {
"id": 38,
"name": "Canada"
},
"province": {
"id": 7,
"name": "British Columbia"
}
},
"modifiedBy": null,
"modifiedDate": null,
"projectPhase": {
"id": 1,
"name": "pre-design"
},
"quotes": [{
"id": 19,
"opportunityValues": {
"Key1": 100,
"Key2 Key2": 100,
"Key3 Key3 Key3": 200,
}
}],
"specForecast": [],
"specIds": [],
"tags": [],
"valuation": "something"
}
I am trying to aggregate using this query in MongoDB. My aggregation key is 4 level deep and also contains spaces. On all online examples shows me the aggregation at the first level. Looking to the online codes, I tried to re-iterate the same with my 4th level deep key.
db.mydata.aggregate([
{$match: {"id": 44328 } } ,
{$group: { _id: "$quotes.id",
totalKey2:{ $sum: "$quotes.opportunityValues.Key2 Key2"},
totalKey3:{ $sum: "$quotes.opportunityValues.Key3 Key3 Key3"}
}
}
]);
This should return
_id totalKey2 totalKey3
0 19 100 300
But it is returning
_id totalKey2 totalKey3
0 19 0 0
What am I doing Wrong?
Although it's not recommended to use space in field names in Mongo, it works as expected.
The problem with your query is that "quotes" is an array and you should first unwind it before grouping it.
This works as expected:
db.mydata.aggregate([
{ $match: { "id": 44328 } } ,
{ $unwind: "$quotes" },
{ $group: { _id: "$quotes.id",
totalKey2:{ $sum: "$quotes.opportunityValues.Key2 Key2" },
totalKey3:{ $sum: "$quotes.opportunityValues.Key3 Key3 Key3" } }
}
]);

Mongo returning an array element

I have the following JSON document in my mongoDB which I added with mingoimport.
I am trying to return a single element from the questions array where theQuestion equals "q1".
{
"questions": [
{
"questionEntry": {
"id": 1,
"info": {
"seasonNumber": 1,
"episodeNumber": 1,
"episodeName": "Days Gone Bye"
},
"questionItem": {
"theQuestion": "q1",
"attachedElement": {
"type": 1,
"value": ""
}
},
"options": [
{
"type": 1,
"value": "o1"
},
{
"type": 1,
"value": "o1"
}
],
"answer": {
"questionId": 1,
"answer": 1
},
"metaTags": [
"Season 1",
"Episode 1",
"Rick Grimmes"
]
}
},
{
"questionEntry": {
"id": 1,
"info": {
"seasonNumber": 1,
"episodeNumber": 1,
"episodeName": "Days Gone Bye"
},
"questionItem": {
"theQuestion": "q2",
"attachedElement": {
"type": 1,
"value": ""
}
},
"options": [
{
"type": 1,
"value": "o2"
},
{
"type": 1,
"value": "o2"
}
],
"answer": {
"questionId": 1,
"answer": 1
},
"metaTags": [
"Season 1",
"Episode 1",
"Rick Grimmes",
"Glenn Rhee"
]
}
}
]
}
I ran the query db.questions.find({"questions.questionEntry.questionItem.theQuestion" : "q1"}) but this retruned the whole document (both questionEntry's in question array!
I have tried db.questions.find({"questions.questionEntry.questionItem.theQuestion" : "q1"}, _id:0," questions.questionItem": {$elemMatch : {theQuestion: "q1"}}})
But get the following error:
Error: error: {
"$err" : "Can't canonicalize query: BadValue Cannot use $elemMatch projection on a nested field.", "code" : 17287
Is there a way I could limit the result to just the array element which contains it?
Thanks
db.questions.find({},{"questions.questionEntry.questionItem.theQuestion" : "q1"});
or
db.questions.find({"questions.questionEntry.questionItem.theQuestion" : "q1"},{'questions.$':1});
please try these.
If you want to use $elemMatch the query should be:
db.questions.find(
{"questions.questionEntry.questionItem.theQuestion" : "q1"},
{
'_id':0,
"questions": {
$elemMatch : {"questionEntry.questionItem.theQuestion": "q1"}
}
}
)

Updating All Nested Arrays in Mongo Object

My data structure is:
{
"_id": { "$oid" : "511D0A0EC075F3FF25000003" },
"progresses": [
{
"behavior": {
"behavior": {
"_id": "511d052f52fbf0fd25000002",
"disabled": false,
"name": "Unity Installed",
"key": "UnityInstalled",
"points": 1,
"timeout": 0
},
"key": "UnityNotInstalled",
"name": "Unity Not Installed",
"points": 1,
"timeout": 0,
"disabled": false,
"_id": { "$oid" : "511D056552FBF0FD25000003" }
},
"behaviorCount": 1,
"behaviorParameter": null,
"userId": null,
"modifiedAt": { "$date": 1360857614000.000000 },
"createdAt": { "$date": 1360857614000.000000 },
"behaviorType": "user"
},
{
"behavior": {
"behavior": {
"_id": "511cfac4955737a01f000001",
"disabled": false,
"name": "test",
"key": "tt",
"points": 1,
"timeout": 0
},
"name": "Unity Installed",
"key": "UnityInstalled",
"points": 1,
"timeout": 0,
"disabled": false,
"_id": { "$oid" : "511D052F52FBF0FD25000002" }
},
"behaviorCount": 3,
"behaviorParameter": null,
"userId": null,
"modifiedAt": { "$date": 1360858565000.000000 },
"createdAt": { "$date": 1360858553000.000000 },
"behaviorType": "user"
},
{
"behavior": {
"behavior": {
"_id": "511d052f52fbf0fd25000002",
"disabled": false,
"name": "Unity Installed",
"key": "UnityInstalled",
"points": 1,
"timeout": 0
},
"name": "Active User",
"key": "ActiveUser",
"points": 1,
"timeout": 0,
"disabled": false,
"_id": { "$oid" : "511D058E52FBF0FD25000004" }
},
"behaviorCount": 1,
"behaviorParameter": null,
"userId": null,
"modifiedAt": { "$date": 1360858565000.000000 },
"createdAt": { "$date": 1360858565000.000000 },
"behaviorType": "user"
},
{
"behavior": {
"behavior": {
"_id": "511d058e52fbf0fd25000004",
"disabled": false,
"name": "Active User",
"key": "ActiveUser",
"points": 1,
"timeout": 0
},
"name": "Invite Count",
"key": "InviteCount",
"points": 1,
"timeout": 0,
"disabled": false,
"_id": { "$oid" : "511D061752FBF0FD25000006" }
},
"behaviorCount": 1,
"behaviorParameter": null,
"userId": null,
"modifiedAt": { "$date": 1360858587000.000000 },
"createdAt": { "$date": 1360858587000.000000 },
"behaviorType": "user"
}
],
"trophyAchievements": [
],
"userId": "asfasd"
}
I want to update all progresses.behaviorCount to 1. How can i done that ?
You should use mongo's positional operator and dot notation.
In your case, I'd use smth like this:
db.test.update({}, {$set: {"progresses.$.behaviorCount": "testing"}}, { multi: true })
But, it won't update all fields in the nested array, just one at a time.
See similar problems:
MongoDB: Updating subdocument
Updating a sub-document in mongodb?
As a workaround, you can loop over nested array and update behaviorCount one at a time by index.
Hope that helps.
This script is the answer:
var i = 0;
db.users.find().forEach(function(doc) {
doc.progresses.forEach(function(progress) {
progress.behaviorCount = 1;
});
db.users.save(doc);
if (i % 10000 == 0) print(i);
i++;
});