Single Element of embedded Array Projection [duplicate] - mongodb

This question already has answers here:
Project first item in an array to new field (MongoDB aggregation)
(3 answers)
Retrieve only the queried element in an object array in MongoDB collection
(18 answers)
Closed 4 years ago.
{
"_id" : ObjectId("5b04e9d891081234f8b69199"),
"simpleType" : "somethingSomething",
"embeddedArray" : [
{
"type" : "theTypeIWant",
"data" : [...]
},
{
"type" : "notThatOne",
"data" : [...]
},
{
"type" : "notThatOne",
"data" : [...]
},
{
"type" : "notThatOne",
"data" : [...]
},
{
"type" : "notThatOne",
"data" : [...]
}
]
}
I have a collection which the documents are structured like my sample above. I already started with an aggregation to match the type I want, but I get the whole array with it which I don't want.
db.collection.aggregate(
[
{$project: {"simpleType" : 1, "embeddedArray.type": 1, "embeddedArray.data": 1}},
{$match: {"embeddedArray.type" : "theTypeIWant"}}
]
)
Is there a way to get only that element of the embeddedArray, that matches the type I am searching for, for my projection?
I cannot guarantee that the element with the type I am searching for will always be the first element in my embedded array.
I would like to have a result set like following:
{
"simpleType" : "somethingSomething",
"type": "theTypeIWant",
"data": [...]
}
or:
{
"simpleType" : "somethingSomething",
"embeddedArray":{
"type": "theTypeIWant",
"data": [...]
}
}

Related

mongodb get object inside array that contains property [duplicate]

This question already has answers here:
Retrieve only the queried element in an object array in MongoDB collection
(18 answers)
Closed 4 years ago.
I have a mongodb table, that contains a fixture of a soccer tournament, so every matchweek looks like this:
"number": 1,
"games" : [
{
"estadio" : "G C",
"arbitro" : "M",
"resultado" : "vs",
"editor" : "Pepe",
"_id" : ObjectId("5af0889e14553f0788bc9db8"),
"equipo_local" : "Las Palmas",
"equipo_visitante" : "Villareal",
"fecha" : "10/05/2018",
"horario" : "16:00",
"hora" : "12:12"
},
{
"estadio" : "Ciudad de Valencia",
"arbitro" : "A Confirmar",
"resultado" : "vs",
"editor" : "No Asignado",
"_id" : ObjectId("5af0889e14553f0788bc9db7"),
"equipo_local" : "Levante",
"equipo_visitante" : "Deportivo",
"fecha" : "28/01/2019",
"horario" : "18:00"
},
..
]
And I want to find all the objects inside "games" of every matchweek that contains "editor" : "pepe",
I've tried something like this
db.fechas.find({"games.editor": "Pepe"})
But that is showing every "games" array that contains an object with "editor": "Pepe", and I want just that specific object, not the whole array.
find method checks whether your nested array contains any document matching your condition and returns entire document.
You need aggregation framework's $filter operator to get a subset of your array, try:
db.fechas.aggregate([
{
$addFields: {
games: {
$filter: {
input: "$games",
as: "game",
cond: {
$eq: [ "$$game.editor", "Pepe" ]
}
}
}
}
},
{
$match: {
$expr: {
$gt: [ { $size: "$games" }, 0 ]
}
}
}
])
EDIT: to remove the documents where games array is empty you can use $match stage specifying condition as expression ($expr) checking array $size

Extract two sub array values in mongodb by $elemMatch

Aggregate, $unwind and $group is not my solution as they make query very slow, there for I am looking to get my record by db.collection.find() method.
The problem is that I need more then one value from sub array. For example from the following example I want to get the "type" : "exam" and "type" : "quiz" elements.
{
"_id" : 22,
"scores" : [
{
"type" : "exam",
"score" : 75.04996547553947
},
{
"type" : "quiz",
"score" : 10.23046475899236
},
{
"type" : "homework",
"score" : 96.72520512117761
},
{
"type" : "homework",
"score" : 6.488940333376703
}
]
}
I am looking something like
db.students.find(
// Search criteria
{ '_id': 22 },
// Projection
{ _id: 1, scores: { $elemMatch: { type: 'exam', type: 'quiz' } }}
)
The result should be like
{ "_id": 22, "scores" : [ { "type" : "exam", "type" : "quiz" } ] }
But this over ride the type: 'exam' and returns only type: 'quiz'. Have anybody any idea how to do this with db.find()?
This is not possible directly using find and elemMatch because of following limitation of elemMatch and mongo array fields.
The $elemMatch operator limits the contents of an field from the query results to contain only the first element matching the $elemMatch condition. ref. from $elemMacth
and mongo array field limitations as below
Only one positional $ operator may appear in the projection document.
The query document should only contain a single condition on the array field being projected. Multiple conditions may override each other internally and lead to undefined behavior. ref from mongo array field limitations
So either you tried following this to find out only exam or quiz
db.collectionName.find({"_id":22,"scores":{"$elemMatch":{"type":"exam"}}},{"scores.$.type":1}).pretty()
is shows only exam scores array.
Otherwise you should go through aggregation

MongoDB fields limitation in array [duplicate]

This question already has answers here:
Retrieve only the queried element in an object array in MongoDB collection
(18 answers)
Closed 8 years ago.
I am looking for a way - and dont even now if this is possible - just to return a part of a list saved in mongodb.
Lets have a look in my currently document:
{
_id : 'MyId',
name : 'a string',
conversations : [
{
user : 'Mike',
input : 'Some input'
},
{
user : 'Stephano',
input : 'some other input'
}
]
}
What I now want to do is smth like this:
var myOutput;
myOutput = db.my_collection.find(
{
_id : 'MyId',
'conversations.user' : 'Mike'
}, {
_id : 1,
name : 1,
conversations : {
$where : {
user : 'Mike'
}
}
});
Goal is it just to get back the conversation array item where user has the value Mike.
Is this still possible in MongoDB ? didn't found any reference in the documentation for the field limitations in mongoDB.
Use the $ positional operator in a projection:
> db.my_collection.find({ "_id" : "MyId", "conversations.user" : "Mike" },
{ "_id" : 1, "name" : 1, "conversations.$" : 1 })
{
"_id" : 'MyId',
"name" : 'a string',
"conversations" : [
{ "user" : 'Mike', "input" : 'Some input' }
]
}
This projects only first matching array element.
Are you aware of the aggregation pipeline?
db.my_collection.aggregate([
{ "$match": { "_id": "MyId"}}, { "$unwind": "$conversations"},
{ "$match": {"conversations.user": "Mike"}}
])
Output
{
"_id" : "MyId",
"name" : "a string",
"conversations" :
{
"user" : "Mike",
"input" : "Some input"
}
}

Getting only Sub Elements [duplicate]

This question already has answers here:
Retrieve only the queried element in an object array in MongoDB collection
(18 answers)
Closed 8 years ago.
If I have the following document
{
"_id" : ObjectId("54986d5531a011bb5fb8e0ee"),
"owner" : "54948a5d85f7a9527a002917",
"type" : "group",
"deleted" : false,
"participants" : [
{ "_id": "54948a5d85f7a9527a002917", "name": "user1" },
{ "_id": "5491234568f7a9527a002918", "name": "user2" },
{ "_id": "5491234568f7a9527a002918", "name": "user3" },
{ "_id": "1234567aaaa7a9527a002917", "name": "user2" }
]
}
How would I get all records where name = 'user2'?
I'm trying the followoing:
db.users.find({ _id: ObjectId('54a7103b1a57eee00bc0a9e4') },
{ 'participants.$.name': 'user2') }).pretty()
...and I get the following:
error: {
"$err" : "Can't canonicalize query: BadValue Positional projection 'participants.$.name' does not match the query document.",
"code" : 17287
}
Though the positional operator($) would give you the first matching element from the participant array. If you need all the participants in with the name user2, you need to aggregate the results.
Match the document with the required _id.
Use the redact operator to only keep all the sub documents that have
participants, who have their name as user2.
Code:
var search = "user2";
db.users.aggregate([
{$match:{"_id":ObjectId("54986d5531a011bb5fb8e0ee")}},
{$redact:{$cond:[{$eq:[{$ifNull:["$name",search]},search]},
"$$DESCEND",
"$$PRUNE"]}},
{$project:{"participants":1,"_id":0}} // set _id:1, if you need the _id.
])
o/p:
{
"participants" : [
{
"_id" : "5491234568f7a9527a002918",
"name" : "user2"
},
{
"_id" : "1234567aaaa7a9527a002917",
"name" : "user2"
}
]
}
Coming to your query,
db.users.find({ _id: ObjectId('54a7103b1a57eee00bc0a9e4') },
{ 'participants.$.name': 'user2'}).pretty()
The positional operator can be applied only on the array, that is referred in the query document of the find function. The above query document doesn't have a reference to the array named participants and only refers to the _id field to match a document. Hence you get the error.
From the docs,
The field being limited must appear in the query document
So, changing the query to include the participants array in the query document would fix the error.
db.users.find({ "_id":ObjectId('54a7103b1a57eee00bc0a9e4'),
"participants.name": "user2"
},
{"participants.$.name":"user2"}).pretty()
But it would return you only the first participant that has matched the criteria in the query document.
From the docs,
Use $ in the projection document of the find() method or the findOne()
method when you only need one particular array element in selected
documents.
o/p:
{
"_id" : ObjectId("54986d5531a011bb5fb8e0ee"),
"participants" : [
{
"_id" : "5491234568f7a9527a002918",
"name" : "user2"
}
]
}

Change _id value from a number to ObjectId()? [duplicate]

This question already has answers here:
How to update the _id of one MongoDB Document?
(7 answers)
Closed 8 years ago.
I have a collection (510 documents) where _id are numbers :
{ "_id" : "1",
"name" : "eric" }
{ "_id" : "2",
"name" : "tom" }
....
and I want to change their values to ObjectId() to be like this:
{ "_id" : ObjectId("53849e258bf3be07804a00d0"),
"name" : "eric" }
{ "_id" : ObjectId("53849e388bf3be07804a00d1"),
"name" : "tom" }
....
so I tried:
db.contacts.find().forEach(function(doc) {
db.contacts.update(
{ "_id": doc._id },
{ "$set": { "_id": ObjectId()} }
);
})
but it doesn't work, I got like result:
Mod on _id not allowed
Thank you.
You cannot change the _id of an Object in a collection once it is created (it is not allowed by mongodb at all). However you could copy the full content of the object execpt of the _id and add your new _id with the ObjectId and insert it into your collection. Afterwards you can remove all the Objects where the _id is a number. It's a bit more complicated but the result is the same (and it works).
Have a look here.