Given a timeseries document like the one below
{
data:{
'2015':['a', 'b', 'c', ...], //<array of n datapoints>
'2016':['d', 'e', 'f', ...], //<array of n datapoints>
},
otherFieldA: {...}
otherFieldB: {...}
}
To get a slice of 2015 I would use the following projection as found here:
myProjection = {'data':0, 'otherFieldA':0, 'otherFieldB':0, 'data.2015':{'$slice': [3, 5]}}
db.collection.find({}, myProjection)
Now let's suppose I also want to get also all of 2016
Option A: adding 'data.2016':1 in the projection above gets a classic inclusion + exclusion mongo error
Option B: adding another $slice to the projection 'data.2016':{'$slice': <len of data.2016>} works but might be time inefficient as mongo needs to scroll down the data.2016 array rather than just scooping up the entire array. Also, I would need to know the lenght of data.2016, which is not a given
Is there a third option to get a slice of data.2015 and all of data.2016, while excluding all the otherField values?
you can do this with the aggregation framework using $project:
db.collection.aggregate([
{
$project:{
"data.2015":{
$slice:[
"$data.2015",
1,
1
]
},
"data.2016":"$data.2016"
}
}
])
output will be :
{
"_id":ObjectId("58492f23f2e6a23e2168649d"),
"data":{
"2015":[
"b"
],
"2016":[
"d",
"e",
"f"
]
}
}
Related
I am working with dynamoose and a query returns me the following output
[ Document { cost: 100 },
lastKey: undefined,
count: 1,
queriedCount: undefined,
timesQueried: 1 ]
When I try to do typeof(output) , it returns Object
When I try to do Object.keys(output) , it returns [ '0', 'lastKey', 'count', 'queriedCount', 'timesQueried' ]
When I do Object.entries(output), it returns [ [ '0', Document { cost: 100 } ],[ 'lastKey', undefined ], [ 'count', 1 ], [ 'queriedCount', undefined ], [ 'timesQueried', 1 ] ]
For my use, I need to get an Object which looks like this {cost: 100} and currently I am using
JSON.parse(JSON.stringify(output))
which gives me
[ { cost: 100 } ]
I havent encountered an object without a key value pair (I'm self taught), so I do not know how to approach this problem. And the current method seems inefficient and kinda wrong. Please advice me how I can do it in a proper way
JSON.stringify(output) //=> "[ { cost: 100 } ]"
What that means is that you have an array (denoted by []) with one item, which is an object (denoted by {}) with a single key cost.
Use [0] to get the first item in an array, and then use .cost to get the cost property.
console.log(output[0].cost) //=> 100
The reason that you are seeing other keys on that array is that it looks like that dynamoose library is adding some additional properties to the array before returning it. It's doing the equivalent of:
// vanilla js, not typescript
const output = [ { cost: 100 } ]
output.count = 1
output.timesQueried = 1
This gives the array properties in addition to the content. The dynamoose library appears to use this method to encode metadata about your queries alongside the returned data.
The default JSON serialization strategy for arrays does not serialize custom array properties, only the array members.
I am facing the following situation:
I have a api request from one service who create multiple mongo documents in one collection for example:
[
{_id: 1, test1: 2, test: 3},
{_id: 2, test1: 3, test: 4}
]
after this a second service read these documents and search another part of the information, so I am building an object like:
[
{_id: 1, newValue: 4},
{_id: 2, newValue: 4}
]
my question is: can I using the "_id" value update all the documents at once ? the problem is that I don't want to update one per one the documents because there are to many, so I am guessing that is better delete all these documents and insert them with all information, what do you think ?
A mass deletion followed by "re-insertion" is a bit heavy handed and will also take its toll on index management. Doing multiple updates in bulk using bulkWrite is the better way:
var bulkOps = [];
for each thing you need to process {
set up _id and newValue ... ;
bulkOps.push({
"updateOne": {
"filter": { "_id": theOneYouAreWorkingOn },
update: { $set: {"newValue": theTargetValue } }
}
});
});
// Send a single big bundle of updates. This could also be wrapped in a transaction:
printjson( db.foo.bulkWrite(bulkOps) );
I'm trying to group the following array acc to dateValue, but can't seem to get it to work. What am I missing here?
const dates = [
{"id":83,"dateValue":"2017-05-24"},
{"id":89,"dateValue":"2017-05-28"},
{"id":91,"dateValue":"2017-05-25"},
{"id":78,"dateValue":"2017-05-24"},
{"id":84,"dateValue":"2017-05-25"}
]
const groups = R.groupWith(R.eqProps('dateValue'),dates)
console.log(groups)
<script src="//cdn.jsdelivr.net/ramda/latest/ramda.min.js"></script>
I've included a link to ramda repl with this code loaded
expected result:
[ [ { dateValue: "2017-05-24", id: 83 },
{ dateValue: "2017-05-24", id: 78 } ],
[ { dateValue: "2017-05-28", id: 89 } ],
[ { dateValue: "2017-05-25", id: 91 } ],
[ { dateValue: "2017-05-25", id: 84 } ] ]
There are several differences between groupBy and groupWith.
groupBy accepts a function which yields a grouping key for a single item. groupWith accepts a binary predicate that says whether two items match.
groupBy collects all items into single collections. groupWith only collects matching itemss which are consecutive.
groupBy returns an object that maps those keys to the list of matching items. groupWith returns a list of lists of (again consecutive) matching items.
It's that second point which is tripping you up. You probably want groupBy:
R.groupBy(R.prop('dateValue'))(dates)
// or
R.compose(R.values, R.groupBy(R.prop('dateValue')))(dates);
You can see this in action on the Ramda REPL.
Given a simple document such as:
{
myArray : [12, 10, 40, -1, -1, ..., -1], //'-1' is a int placeholder
latestUpdatedIndex : 2
}
I know how many values I will put in myArray so I preallocate space with the -1 values to make updates more efficient. I keep track of the latest value I updated in latestUpdatedIndex
Can I use the value of latestUpdatedIndex in a $slice projection like the one below?
coll.find({}, {'myArray':{'$slice':[0, <value of latestUpdatedIndex>]}
You can't do that using a normal query but you can do it using aggregation (in MongoDB 3.2):
db.collection.aggregate([
{ $project: { mySlicedArray: { $slice: [ "$myArray", "$latestUpdatedIndex" ] } } }
])
I have the following documents:
{
_id: 1
title: "oneItem"
},
{
_id: 2,
title: "twoItem"
}
When I try to find these documents by using the following command:
db.collection.documents.find({_id: {$in: [1, 2]}});
I get these two documents but when I try to find these documents by using the following query:
db.collection.documents.find({_id: {$all: [1, 2]}});
I get nothing. Can you explain what's the problem? Basically I need to find all documents with _id 1 and 2 and if none exist then fail.
The reasoning is actually quite simple in that $in and $all have two completely different functions. The documentation links are there, but to explain:
Consider these documents:
{
_id: 1,
items: [ "a", "b" ]
},
{
_id: 2,
items: [ "a", "b", "c" ]
}
$in - provides a list of arguments that can possibly match the value in the field being tested. This would match as follows:
db.collection.find({ items: {$in: [ "a", "b", "c" ] }})
{
_id: 1,
items: [ "a", "b" ]
},
{
_id: 2,
items: [ "a", "b", "c" ]
}
$all - provides a list where the field being matched is expected to be an array and all of the listed elements are present in that array. E.g
db.collection.find({ items: {$all: [ "a", "b", "c" ] }})
{
_id: 2,
items: [ "a", "b", "c" ]
}
Hence why your query does not return a result, the field is not an array and does not contain both elements.
The MongoDB operator reference is something you should really read through.
As your your statement, ["I need to find all documents with _id 1 and 2 and if someone from them does not exists then fail."], matching various criteria is easy as you see in the usage of $in. Your problem is you want a whole set to match or otherwise return nothing ("fail"). This I have already explained to you an some length in a previous question, but to re-iterate:
db.collection.aggregate([
// Match on what you want to find
{$match: { list: {$in: [1,2]} }},
// Add the found results to a distinct *set*
{$group: { _id: null, list: {$addToSet: "$_id"} }},
// Only return when *all* the expected items are in the *set*
{$match: { list: {$all: [1,2]} }}
])
So after that manipulation, this will only return a result if all of the items where found. That is how we use $all to match in this way.