How to find document by parts of ObjectId? - mongodb

For some reason I use MongoDB native ObjectId as primary key for ticket identification number for my application. Is it possible to search documents with ObjectId parts?
For example: I have documents:
[
{_id: ObjectId("577f8e6537e4a676203c056a")},
{_id: ObjectId("577f8ee437e4a676203c0577")},
{_id: ObjectId("577f8f3d717b6fdd22a1684c")}
]
And I want to query it by its _id contains "0577" so that it returns
{_id: ObjectId("577f8ee437e4a676203c0577")}
I have tried regex before. It returned []
db.transaction.find({_id: /0577/i}) ---> return 0
db.transaction.find({_id: {$regex: /0577/, $options: "i"}}) ---> return 0

I think you can use $where like this:
db.transaction.find({ $where: "this._id.str.match(/.*0577/)" })

Related

MongoDB: find document whose subdocument contains a given value

Given is a Document like the following
{
"type" : "sometype",
"title" : "sometitle",
"references":{
"1": "someref",
"2": "otherref",
"3": ""
}
}
How can I find all documents which have the reference someref set in the subdocument references?
A simple find({references: "someref"}) doesn't work because references is not a valid array.
Document structure is not ideal for this kind of queries but you can use aggregation with $objectToArray operator:
db.collection.aggregate([
{$addFields: {refs: {$objectToArray: "$references"}}},
{$match: {"refs.v": "someref"}},
{$project:{refs: 0}}
])
If the number of subdocument fields you are looking into is small, then you can simply filter your collection using $or
db.collection.find(
{ $or: [
{"references.1": "someref"},
{"references.2": "someref"},
{"references.3": "someref"}
]} )

How do I project an element of an array in mongo?

I have a mongo document that contains something like
{date: [2018, 3, 22]}
and when I try to project this into a flat JSON structure with these fields concatenated, I always get an array with 0 elements, eg. just extracting the year with
db.getCollection('blah').aggregate([
{$project: {year: "$date.0"}}
])
I get
{"year" : []}
even though matching on a similar expression works fine, eg.
db.getCollection('blah').aggregate([
{$match: {"$date.0": 2018}}
])
selects the documents I would expect just fine.
What am I doing wrong? I've searched mongo documentation and stackoverflow but could find nothing.
For $project you should use $arrayElemAt instead of dot notation which works only for queries.
db.getCollection('blah').aggregate([
{$project: {year: { $arrayElemAt: [ "$date", 0 ] }}}
])
More here

Mongo Upsert with values of find $in

I have to run mongo updates by querying that the user id is in an array. Is it possible to upsert any values not in the array?
Eg:
db.collection.update({
userId:{
$in:['1','2', '3']
}
},
{$set: {score:30}},
{upsert:true})
If I run this query I get one new doc with _id and score. What I'd like to do is have a new doc for each userId not present in the userId array:
[{userId:1, score:30, _id:...}, {userId:2, score: 30, _id: ...}, ...]
Is this possible in mongo?
No, this cannot be done. The documentation states:
If upsert is true and no document matches the query criteria, update() inserts a single document.

mongo find limit each match

I have a mongo collection which looks something like this:
{
title: String,
category: String
}
I want to write a query that selects various categories, similar to this:
Collection.find({category: {$in: ['Books', 'Cars', 'People']});
But I want to only select a limited number of each category, for example 5 of each book, car, people. How do I write such a query? Can I do it one query or must I use multiple ones?
You can do it using mongodb aggregation. Take a look at this pipeline:
Filter all documents by categories(using $match).
Group data by categories and create array for items with the same category(using $group and $push).
Get a subset of each array with a limited maximum length(using $project and $slice).
Try the following query:
db.collection.aggregate([
{$match: {category: {$in: ['Books', 'Cars', 'People']}}},
{$group: {_id: "$category", titles: {$push: "$title"}}},
{$project: {titles: {$slice: ["$titles", 5]}}}
])

Retrieve Array Of Documents in MongoDB

I have a MongoDB Document like as follows
{
"_id":1,
"name":"XYZ"
ExamScores:[
{ExamName:"Maths", UnitTest:1, Score:100},
{ExamName:"Maths", UnitTest:2, Score:80},
{ExamName:"Science", UnitTest:1, Score:90}
]
}
I Need to retrieve this document so that it has to show only Maths Array. Like as follows
{
"_id":1,
"name":"XYZ"
ExamScores:[
{ExamName:"Maths", UnitTest:1, Score:100},
{ExamName:"Maths", UnitTest:2, Score:80},
]
}
How Can I Do That ?
As #karin states there is no, normal, in query method of doing this.
In version 2.2 you can use $elemMatch to project the first matching result from ExamScores but you cannot get multiple.
That being said, the aggregation framework can do this:
db.col.aggregate([
{$unwind: '$ExamScores'},
{$match: {'ExamScores.ExamName':"Maths"}},
{$group: {_id: '$_id', name: '$name', ExamScores: {$push: '$ExamScores'}}}
])
Something like that anyway.
This has been asked before MongoDB query to limit values based on condition, the only answer there says it is not possible, but that there is a request to implement that.